nothumanallowed 13.2.95 → 13.2.96
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 +51 -45
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +68 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.96",
|
|
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
|
@@ -3338,55 +3338,61 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS (use only what is RELEVANT to the wo
|
|
|
3338
3338
|
// Strip think tags from fullOutput before emptiness check
|
|
3339
3339
|
let fullOutputClean = fullOutput.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
3340
3340
|
|
|
3341
|
-
// ── Fill empty sections
|
|
3342
|
-
// Detect headings with no body: heading immediately followed by another heading or end
|
|
3343
|
-
//
|
|
3344
|
-
const
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
sendToken('\n\n[Completando sezioni mancanti...] ');
|
|
3354
|
-
// Pass raw data AND the partial report already written so the model writes in context
|
|
3341
|
+
// ── Fill empty sections — iterative loop until no empty sections remain ─────
|
|
3342
|
+
// Detect headings with no body: heading immediately followed by another heading or end.
|
|
3343
|
+
// We loop because filling section A may expose B, C, D that were skipped by detection.
|
|
3344
|
+
const getEmptySections = (text) => {
|
|
3345
|
+
const rx = /^(#{1,4}\s+[^\n]+)\n+(?=#{1,4}\s|$)/gm;
|
|
3346
|
+
const found = [];
|
|
3347
|
+
let m;
|
|
3348
|
+
while ((m = rx.exec(text)) !== null) found.push(m[1].trim());
|
|
3349
|
+
return found;
|
|
3350
|
+
};
|
|
3351
|
+
|
|
3352
|
+
if (!isCanvasAgent) {
|
|
3355
3353
|
const dataForFill = (toolData || context || '').slice(0, 4000);
|
|
3356
3354
|
const fillConfig = Object.assign({}, config, { thinking: 'off' });
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
)
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3355
|
+
let fillRound = 0;
|
|
3356
|
+
const MAX_FILL_ROUNDS = 3; // safety cap — never more than 3 passes
|
|
3357
|
+
let emptySections = getEmptySections(fullOutputClean);
|
|
3358
|
+
|
|
3359
|
+
while (emptySections.length > 0 && fillRound < MAX_FILL_ROUNDS) {
|
|
3360
|
+
fillRound++;
|
|
3361
|
+
if (fillRound === 1) sendToken('\n\n[Completando sezioni mancanti...] ');
|
|
3362
|
+
for (const emptyHeading of emptySections) {
|
|
3363
|
+
sendToken('\n' + emptyHeading + '\n');
|
|
3364
|
+
let filledContent = '';
|
|
3365
|
+
const reportSoFar = fullOutputClean.slice(-3000);
|
|
3366
|
+
try {
|
|
3367
|
+
await withTimeout(
|
|
3368
|
+
callLLMStream(
|
|
3369
|
+
fillConfig,
|
|
3370
|
+
`You are ${agent}. You wrote a report and accidentally left one section empty. Fill in ONLY the missing section — do NOT repeat the heading, do NOT add other sections. Be specific, consistent with the rest of the report, and thorough. Write in ${language}.\n\nSource data:\n${dataForFill}\n\nOverall task: ${task}\n\nReport written so far (for context and style consistency):\n${reportSoFar}`,
|
|
3371
|
+
`Write ONLY the body content for this section (heading already printed, do not repeat it):\n${emptyHeading}`,
|
|
3372
|
+
(tok) => { filledContent += tok; sendToken(tok); },
|
|
3373
|
+
{ max_tokens: 1500, thinking: 'off' }
|
|
3374
|
+
),
|
|
3375
|
+
45000
|
|
3376
|
+
);
|
|
3377
|
+
} catch {}
|
|
3378
|
+
if (filledContent.trim()) {
|
|
3379
|
+
const escapedH = emptyHeading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3380
|
+
// Inject after heading when followed by another heading
|
|
3381
|
+
fullOutputClean = fullOutputClean.replace(
|
|
3382
|
+
new RegExp('(' + escapedH + ')\\n+(#{1,4}\\s)', 'g'),
|
|
3383
|
+
'$1\n\n' + filledContent.trim() + '\n\n$2'
|
|
3384
|
+
);
|
|
3385
|
+
// Inject at end of document (trailing heading)
|
|
3386
|
+
fullOutputClean = fullOutputClean.replace(
|
|
3387
|
+
new RegExp('(' + escapedH + ')\\s*$', 'g'),
|
|
3388
|
+
'$1\n\n' + filledContent.trim()
|
|
3389
|
+
);
|
|
3390
|
+
}
|
|
3386
3391
|
}
|
|
3392
|
+
// Re-detect after this round — newly injected content may close all gaps
|
|
3393
|
+
emptySections = getEmptySections(fullOutputClean);
|
|
3387
3394
|
}
|
|
3388
|
-
|
|
3389
|
-
// Remove empty sections if we can't fill them (fallback: no data available)
|
|
3395
|
+
// Strip any unfillable trailing headings
|
|
3390
3396
|
fullOutputClean = fullOutputClean.replace(/^(#{1,4}\s+[^\n]+)\n+(?=#{1,4}\s|$)/gm, '');
|
|
3391
3397
|
}
|
|
3392
3398
|
// Strip trailing lone headings at end of output (truly unfillable)
|
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.96';
|
|
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
|
@@ -677,11 +677,21 @@ function openCanvasPanel(){
|
|
|
677
677
|
var cp = document.getElementById('canvasPanel');
|
|
678
678
|
if (!cp) return;
|
|
679
679
|
cp.classList.add('open');
|
|
680
|
-
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
if (cf)
|
|
684
|
-
|
|
680
|
+
var cf = document.getElementById('canvasFrame');
|
|
681
|
+
if (studioState.canvas) {
|
|
682
|
+
// Re-inject canvas HTML — survives panel close/reopen
|
|
683
|
+
if (cf) cf.srcdoc = studioState.canvas;
|
|
684
|
+
var ct = document.getElementById('canvasTitle');
|
|
685
|
+
if (ct && ct.textContent === 'Canvas') ct.textContent = 'Studio Report';
|
|
686
|
+
} else {
|
|
687
|
+
// Check allCanvasData for current conversation
|
|
688
|
+
var d = getConvCanvasData();
|
|
689
|
+
if (d.canvases.length > 0) {
|
|
690
|
+
canvasMode = 'canvas';
|
|
691
|
+
canvasIdx = d.canvases.length - 1;
|
|
692
|
+
renderCanvasPanel();
|
|
693
|
+
} else if (cf) {
|
|
694
|
+
var tip = '<!DOCTYPE html><html><body style="background:#0a0a0a;color:#6b7280;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;text-align:center;padding:20px"><div><div style="font-size:32px;margin-bottom:16px">■</div><div style="font-size:13px;line-height:1.6">Nessun Canvas in questo workflow.<br>Aggiungi <strong style="color:#4ade80">html</strong>, <strong style="color:#4ade80">dashboard</strong> o <strong style="color:#4ade80">visual</strong> al prompt,<br>oppure usa un task con 2+ agenti specialisti.</div></div></body></html>';
|
|
685
695
|
cf.srcdoc = tip;
|
|
686
696
|
}
|
|
687
697
|
}
|
|
@@ -3700,52 +3710,81 @@ function downloadStudioPDF() {
|
|
|
3700
3710
|
'.section-title{color:#4f46e5!important}}</style>';
|
|
3701
3711
|
var pdfHtml = html.replace('</head>', printCss + '</head>');
|
|
3702
3712
|
|
|
3703
|
-
//
|
|
3713
|
+
// Inject light-mode overrides for PDF — dark backgrounds become unreadable on paper
|
|
3714
|
+
var lightOverride = '<style>' +
|
|
3715
|
+
'body{background:#ffffff!important;color:#1a1a2e!important;padding:28px!important;max-width:760px!important;margin:0 auto!important}' +
|
|
3716
|
+
'.header{background:linear-gradient(135deg,#4f46e5 0%,#06b6d4 100%)!important;-webkit-print-color-adjust:exact!important;color-adjust:exact!important}' +
|
|
3717
|
+
'.header h1,.header p,.meta span{color:#fff!important}' +
|
|
3718
|
+
'.card,.section{background:#f4f6fb!important;border:1px solid #dde1ee!important}' +
|
|
3719
|
+
'.card h3,.section h3,.section-title,.card-label{color:#4f46e5!important}' +
|
|
3720
|
+
'.card p,.section p,ul li,ol li{color:#374151!important}' +
|
|
3721
|
+
'.priority-item{background:#eef0f8!important}' +
|
|
3722
|
+
'.priority-item h4{color:#1a1a2e!important}' +
|
|
3723
|
+
'.priority-item p{color:#374151!important}' +
|
|
3724
|
+
'.source-item{background:#eef0f8!important;border-left-color:#4f46e5!important}' +
|
|
3725
|
+
'.source-item h4{color:#1a1a2e!important}' +
|
|
3726
|
+
'.source-item p{color:#374151!important}' +
|
|
3727
|
+
'.bar-track{background:#e0e4ef!important}' +
|
|
3728
|
+
'.footer{color:#9ca3af!important}' +
|
|
3729
|
+
'a{color:#4f46e5!important}' +
|
|
3730
|
+
'.section,.card,.priority-item,.source-item,.bar-row{break-inside:avoid;page-break-inside:avoid}' +
|
|
3731
|
+
'h1,h2,h3,h4{break-after:avoid;page-break-after:avoid}' +
|
|
3732
|
+
'.header{break-after:avoid;page-break-after:avoid}' +
|
|
3733
|
+
'</style>';
|
|
3734
|
+
var pdfHtml2 = html.replace('</head>', lightOverride + '</head>');
|
|
3735
|
+
|
|
3736
|
+
// Build hidden iframe at 794px (A4 width at 96dpi = 210mm)
|
|
3704
3737
|
var iframe = document.createElement('iframe');
|
|
3705
|
-
iframe.style.cssText = 'position:fixed;left:-9999px;top:0;width:
|
|
3738
|
+
iframe.style.cssText = 'position:fixed;left:-9999px;top:0;width:794px;height:1px;border:none;visibility:hidden';
|
|
3706
3739
|
document.body.appendChild(iframe);
|
|
3707
3740
|
var ifrDoc = iframe.contentDocument || iframe.contentWindow.document;
|
|
3708
|
-
ifrDoc.open(); ifrDoc.write(
|
|
3741
|
+
ifrDoc.open(); ifrDoc.write(pdfHtml2); ifrDoc.close();
|
|
3709
3742
|
iframe.onload = function() {
|
|
3710
|
-
var
|
|
3711
|
-
var totalH = Math.max(
|
|
3743
|
+
var ifrBody = ifrDoc.body;
|
|
3744
|
+
var totalH = Math.max(ifrBody.scrollHeight, ifrBody.offsetHeight, ifrDoc.documentElement.scrollHeight);
|
|
3712
3745
|
iframe.style.height = totalH + 'px';
|
|
3713
|
-
//
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3746
|
+
// Scale: 3x on HiDPI screens, minimum 2.5x for sharp text at A4
|
|
3747
|
+
var renderScale = Math.max(2.5, Math.min(3, window.devicePixelRatio * 1.5));
|
|
3748
|
+
window.html2canvas(ifrBody, {
|
|
3749
|
+
scale: renderScale,
|
|
3750
|
+
useCORS: true,
|
|
3751
|
+
allowTaint: true,
|
|
3752
|
+
backgroundColor: '#ffffff',
|
|
3753
|
+
width: 794,
|
|
3754
|
+
windowWidth: 794,
|
|
3755
|
+
scrollX: 0,
|
|
3756
|
+
scrollY: 0,
|
|
3757
|
+
logging: false,
|
|
3758
|
+
imageTimeout: 15000,
|
|
3759
|
+
ignoreElements: function(el){ return el.tagName === 'SCRIPT' || el.tagName === 'NOSCRIPT'; }
|
|
3720
3760
|
}).then(function(canvas) {
|
|
3721
|
-
var imgData = canvas.toDataURL('image/png'); // PNG for crisp text
|
|
3722
3761
|
var pdf = new window.jspdf.jsPDF({orientation:'portrait', unit:'pt', format:'a4', compress:true});
|
|
3723
|
-
var pageW = pdf.internal.pageSize.getWidth(); //
|
|
3724
|
-
var pageH = pdf.internal.pageSize.getHeight(); //
|
|
3725
|
-
var margin =
|
|
3762
|
+
var pageW = pdf.internal.pageSize.getWidth(); // 595.28pt
|
|
3763
|
+
var pageH = pdf.internal.pageSize.getHeight(); // 841.89pt
|
|
3764
|
+
var margin = 28; // pt — ~10mm margins
|
|
3726
3765
|
var usableW = pageW - margin * 2;
|
|
3727
3766
|
var usableH = pageH - margin * 2;
|
|
3728
|
-
// Scale image to fit page width
|
|
3729
|
-
var imgW = usableW;
|
|
3730
|
-
var imgH = (canvas.height * usableW) / canvas.width;
|
|
3731
3767
|
|
|
3732
|
-
//
|
|
3733
|
-
|
|
3734
|
-
var sliceH = Math.floor(
|
|
3768
|
+
// px per rendered page = canvas pixels that map to usableH in pt
|
|
3769
|
+
var pxPerPt = canvas.width / usableW;
|
|
3770
|
+
var sliceH = Math.floor(usableH * pxPerPt); // canvas px per A4 page
|
|
3771
|
+
|
|
3735
3772
|
var yCanvas = 0;
|
|
3736
3773
|
var pageNum = 0;
|
|
3737
3774
|
while (yCanvas < canvas.height) {
|
|
3738
3775
|
if (pageNum > 0) pdf.addPage();
|
|
3739
3776
|
var remaining = canvas.height - yCanvas;
|
|
3740
3777
|
var thisSlice = Math.min(sliceH, remaining);
|
|
3741
|
-
// Create a temporary canvas for this slice
|
|
3742
3778
|
var sliceCanvas = document.createElement('canvas');
|
|
3743
3779
|
sliceCanvas.width = canvas.width;
|
|
3744
3780
|
sliceCanvas.height = thisSlice;
|
|
3745
3781
|
var ctx = sliceCanvas.getContext('2d');
|
|
3782
|
+
ctx.fillStyle = '#ffffff';
|
|
3783
|
+
ctx.fillRect(0, 0, sliceCanvas.width, sliceCanvas.height);
|
|
3746
3784
|
ctx.drawImage(canvas, 0, yCanvas, canvas.width, thisSlice, 0, 0, canvas.width, thisSlice);
|
|
3747
3785
|
var sliceData = sliceCanvas.toDataURL('image/png');
|
|
3748
|
-
|
|
3786
|
+
// Proportional height in pt: thisSlice / pxPerPt
|
|
3787
|
+
var sliceImgH = thisSlice / pxPerPt;
|
|
3749
3788
|
pdf.addImage(sliceData, 'PNG', margin, margin, usableW, sliceImgH, '', 'FAST');
|
|
3750
3789
|
yCanvas += thisSlice;
|
|
3751
3790
|
pageNum++;
|