nothumanallowed 13.5.86 → 13.5.88
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/services/web-ui.mjs +162 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.88",
|
|
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/services/web-ui.mjs
CHANGED
|
@@ -6528,7 +6528,11 @@ var wcState = {
|
|
|
6528
6528
|
logs: [],
|
|
6529
6529
|
error: null
|
|
6530
6530
|
},
|
|
6531
|
-
lastGenStats: null
|
|
6531
|
+
lastGenStats: null,
|
|
6532
|
+
repairing: false,
|
|
6533
|
+
repairTotal: 0,
|
|
6534
|
+
repairDone: 0,
|
|
6535
|
+
repairCurrent: ''
|
|
6532
6536
|
};
|
|
6533
6537
|
var wcRightTab = 'files';
|
|
6534
6538
|
var wcMainTab = 'new'; // 'new' | 'projects'
|
|
@@ -6550,6 +6554,8 @@ var _wcOverlayTimer = null; // inactivity timer to restore overlay
|
|
|
6550
6554
|
var _wcGenAbortCtrl = null; // AbortController for generation stop
|
|
6551
6555
|
var _wcSyntaxResults = []; // [{file, ok, error}]
|
|
6552
6556
|
var _wcSnapshots = []; // [{ts, fileCount}]
|
|
6557
|
+
var _wcLastFilePlan = []; // saved for manual repair trigger
|
|
6558
|
+
var _wcLastSysPreamble = '';
|
|
6553
6559
|
// Skills state
|
|
6554
6560
|
var wcSkills = []; // [{name, content, type}] type: 'skill'|'memory'|'provider'
|
|
6555
6561
|
var wcSkillModal = null; // null | {mode:'edit'|'new', idx:number|null, name, content, type, generating}
|
|
@@ -6565,31 +6571,68 @@ var WC_DEFAULT_FILES = [
|
|
|
6565
6571
|
function wcEsc(s){return s?String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'):''}
|
|
6566
6572
|
|
|
6567
6573
|
function renderWebCraft(el) {
|
|
6568
|
-
|
|
6569
|
-
|
|
6574
|
+
// File sidebar — replaces horizontal tabs
|
|
6575
|
+
var _activeFile = wcState.generatedFiles[wcState.activeFile];
|
|
6576
|
+
|
|
6577
|
+
function wcFileSizeLabel(content) {
|
|
6578
|
+
if (!content) return '0 B';
|
|
6579
|
+
var bytes = new TextEncoder().encode(content).length;
|
|
6580
|
+
if (bytes < 1024) return bytes + ' B';
|
|
6581
|
+
if (bytes < 1024*1024) return (bytes/1024).toFixed(1) + ' KB';
|
|
6582
|
+
return (bytes/(1024*1024)).toFixed(2) + ' MB';
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6585
|
+
var fileSidebarHtml = wcState.generatedFiles.length > 0
|
|
6586
|
+
? '<div style="width:190px;flex-shrink:0;border-left:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column">' +
|
|
6587
|
+
'<div style="padding:8px 10px;border-bottom:1px solid var(--border);font-size:9px;color:var(--dim);text-transform:uppercase;letter-spacing:.8px;flex-shrink:0">'+wcState.generatedFiles.length+' file</div>' +
|
|
6570
6588
|
wcState.generatedFiles.map(function(f,i){
|
|
6571
6589
|
var active = i === wcState.activeFile;
|
|
6572
6590
|
var hasErr = !!f._error || !!f._syntaxError;
|
|
6573
6591
|
var isPending = !!f._pending;
|
|
6574
|
-
var
|
|
6575
|
-
var
|
|
6576
|
-
var
|
|
6577
|
-
|
|
6592
|
+
var lines = isPending ? 0 : (f.content || '').split(String.fromCharCode(10)).length;
|
|
6593
|
+
var sizeLabel = isPending ? '...' : wcFileSizeLabel(f.content || '');
|
|
6594
|
+
var nameColor = hasErr ? '#f87171' : isPending ? '#4b5563' : active ? 'var(--text)' : 'var(--dim)';
|
|
6595
|
+
var bg = active ? 'var(--bg3)' : 'transparent';
|
|
6596
|
+
var borderLeft = hasErr ? '2px solid #f87171' : active ? '2px solid var(--green3)' : '2px solid transparent';
|
|
6597
|
+
var icon = isPending ? '⌛' : hasErr ? '⚠' : wcFileIcon(f.name);
|
|
6598
|
+
return '<button id="wcTab'+i+'" onclick="wcSetFile('+i+')" style="width:100%;text-align:left;padding:7px 10px 7px 10px;background:'+bg+';border:none;border-left:'+borderLeft+';cursor:pointer;display:flex;flex-direction:column;gap:2px;flex-shrink:0">' +
|
|
6599
|
+
'<span style="display:flex;align-items:center;gap:5px">' +
|
|
6600
|
+
'<span style="font-size:12px;flex-shrink:0">'+icon+'</span>' +
|
|
6601
|
+
'<span style="font-size:11px;font-family:var(--mono);color:'+nameColor+';overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1" title="'+wcEsc(f.name)+'">'+wcEsc(f.name.split('/').pop())+'</span>' +
|
|
6602
|
+
'</span>' +
|
|
6603
|
+
(f.name.includes('/') ? '<span style="font-size:9px;color:#4b5563;font-family:var(--mono);padding-left:17px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+wcEsc(f.name.split('/').slice(0,-1).join('/'))+'</span>' : '') +
|
|
6604
|
+
(!isPending ? '<span style="font-size:9px;color:#4b5563;font-family:var(--mono);padding-left:17px">'+lines+' righe · '+sizeLabel+'</span>' : '') +
|
|
6605
|
+
'</button>';
|
|
6578
6606
|
}).join('') +
|
|
6579
6607
|
'</div>'
|
|
6580
6608
|
: '';
|
|
6581
6609
|
|
|
6582
|
-
var _activeFile = wcState.generatedFiles[wcState.activeFile];
|
|
6583
6610
|
var codeHtml = wcState.generatedFiles.length > 0 && _activeFile
|
|
6584
|
-
? '<div
|
|
6585
|
-
|
|
6586
|
-
|
|
6611
|
+
? '<div style="flex:1;display:flex;flex-direction:row;min-height:0;overflow:hidden">' +
|
|
6612
|
+
'<div id="wcCodeWrap" style="flex:1;overflow:auto;background:var(--bg3)">' +
|
|
6613
|
+
'<div style="padding:8px 14px;border-bottom:1px solid var(--border2);font-size:10px;color:var(--dim);font-family:var(--mono);display:flex;align-items:center;gap:8px;background:var(--bg2)">' +
|
|
6614
|
+
'<span style="font-size:13px">'+wcFileIcon(_activeFile.name)+'</span>' +
|
|
6615
|
+
'<span style="color:var(--text)">'+wcEsc(_activeFile.name)+'</span>' +
|
|
6616
|
+
(!_activeFile._pending && !_activeFile._error ? '<span style="margin-left:auto;color:#4b5563">'+(_activeFile.content||'').split(String.fromCharCode(10)).length+' righe · '+wcFileSizeLabel(_activeFile.content||'')+'</span>' : '') +
|
|
6617
|
+
'</div>' +
|
|
6618
|
+
(_activeFile._error ? '<div style="padding:8px 14px;background:rgba(239,68,68,0.12);border-bottom:1px solid rgba(239,68,68,0.3);font-size:11px;color:#f87171;display:flex;align-items:center;gap:6px">⚠ Generazione fallita — chiedi al modello di rigenerare questo file</div>' :
|
|
6619
|
+
_activeFile._syntaxError ? '<div style="padding:8px 14px;background:rgba(234,179,8,0.1);border-bottom:1px solid rgba(234,179,8,0.3);font-size:11px;color:#facc15;display:flex;align-items:center;gap:6px">⚠ Syntax error: '+wcEsc(_activeFile._syntaxError)+'</div>' : '') +
|
|
6620
|
+
(_activeFile._pending ? '<div style="display:flex;align-items:center;justify-content:center;height:120px;color:var(--dim);font-size:12px;gap:8px">⌛ In generazione...</div>' :
|
|
6621
|
+
'<pre style="margin:0;padding:14px 16px;font-size:11px;line-height:1.6;color:'+(_activeFile._error?'#f87171':_activeFile._syntaxError?'#fde68a':'var(--text)')+';font-family:var(--mono);white-space:pre-wrap;word-break:break-all">'+wcEsc(_activeFile.content)+'</pre>') +
|
|
6622
|
+
'</div>' +
|
|
6623
|
+
fileSidebarHtml +
|
|
6587
6624
|
'</div>'
|
|
6588
6625
|
: '<div style="flex:1;display:flex;align-items:center;justify-content:center;color:var(--dim);font-size:12px;flex-direction:column;gap:8px">' +
|
|
6589
6626
|
'<span style="font-size:36px;opacity:.25">🛠</span>' +
|
|
6590
6627
|
'<span>'+t('wc_no_files')+'</span>' +
|
|
6591
6628
|
'</div>';
|
|
6592
6629
|
|
|
6630
|
+
function wcFileIcon(name) {
|
|
6631
|
+
var ext = name.split('.').pop().toLowerCase();
|
|
6632
|
+
var icons = { js:'📄', ts:'📄', css:'🎨', html:'🌐', json:'{', md:'📑', sql:'🗂', env:'🔐', conf:'⚙', lock:'🔒' };
|
|
6633
|
+
return icons[ext] || '📄';
|
|
6634
|
+
}
|
|
6635
|
+
|
|
6593
6636
|
var authFieldsHtml = wcState.authFields.map(function(f,i){
|
|
6594
6637
|
return '<div style="display:flex;align-items:center;gap:6px;padding:5px 8px;background:var(--bg3);border-radius:6px;margin-bottom:4px;overflow:hidden">' +
|
|
6595
6638
|
'<input value="'+wcEsc(f.label)+'" onchange="wcUpdateField('+i+',this.value)" style="flex:1;min-width:0;background:transparent;border:none;color:var(--text);font-size:11px;font-family:var(--mono);width:0" />' +
|
|
@@ -6657,6 +6700,13 @@ function renderWebCraft(el) {
|
|
|
6657
6700
|
(wcState.running ?
|
|
6658
6701
|
'<div style="width:100%;padding:11px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--dim);font-size:12px;text-align:center">⏳ '+t('wc_generating')+'...</div>'
|
|
6659
6702
|
: '') +
|
|
6703
|
+
(wcState.repairing ?
|
|
6704
|
+
'<div style="width:100%;padding:10px 12px;background:rgba(234,179,8,0.08);border:1px solid rgba(234,179,8,0.4);border-radius:8px;display:flex;flex-direction:column;gap:4px">' +
|
|
6705
|
+
'<div style="display:flex;align-items:center;gap:6px;font-size:11px;color:#facc15;font-weight:600">🔧 Correzione automatica in corso...</div>' +
|
|
6706
|
+
'<div style="font-size:10px;color:var(--dim)">'+wcState.repairDone+' / '+wcState.repairTotal+' file</div>' +
|
|
6707
|
+
(wcState.repairCurrent ? '<div style="font-size:10px;color:#fde68a;font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+wcEsc(wcState.repairCurrent)+'</div>' : '') +
|
|
6708
|
+
'</div>'
|
|
6709
|
+
: '') +
|
|
6660
6710
|
(wcState.generatedFiles.length > 0 && !wcState.running ?
|
|
6661
6711
|
'<div style="display:flex;gap:6px;flex-wrap:wrap">' +
|
|
6662
6712
|
'<button onclick="wcDownloadZip()" style="flex:1;padding:9px;background:var(--bg3);border:1px solid var(--border2);border-radius:8px;color:var(--text);font-size:11px;font-weight:600;cursor:pointer">⇩ ZIP</button>' +
|
|
@@ -6664,6 +6714,9 @@ function renderWebCraft(el) {
|
|
|
6664
6714
|
'<button onclick="wcToggleGrep()" title="Cerca nel codice" style="padding:9px 10px;background:'+(_wcGrepOpen?'var(--greendim)':'var(--bg3)')+';border:1px solid '+(_wcGrepOpen?'var(--green3)':'var(--border2)')+';border-radius:8px;color:'+(_wcGrepOpen?'var(--green)':'var(--dim)')+';font-size:11px;cursor:pointer">🔍</button>' +
|
|
6665
6715
|
'<button onclick="wcManualSnapshot()" title="Salva snapshot" style="padding:9px 10px;background:var(--bg3);border:1px solid var(--border2);border-radius:8px;color:var(--dim);font-size:11px;cursor:pointer">💾</button>' +
|
|
6666
6716
|
'</div>' +
|
|
6717
|
+
(wcState.generatedFiles.some(function(f){ return f._error || f._syntaxError; }) && !wcState.repairing ?
|
|
6718
|
+
'<button onclick="wcTriggerRepair()" style="width:100%;padding:9px;background:rgba(234,179,8,0.08);border:1px solid rgba(234,179,8,0.5);border-radius:8px;color:#facc15;font-size:11px;font-weight:600;cursor:pointer">🔧 Correggi tutti i file rossi</button>'
|
|
6719
|
+
: '') +
|
|
6667
6720
|
'<button onclick="wcStartSandbox()" id="wcSandboxBtn" style="width:100%;padding:10px;background:var(--bg3);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;font-weight:600;cursor:pointer">▶ '+t('wc_sandbox_start')+'</button>' +
|
|
6668
6721
|
(wcState.lastGenStats ? '<div style="padding:6px 8px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;font-size:10px;color:var(--dim);font-family:var(--mono);display:flex;flex-wrap:wrap;gap:6px">' +
|
|
6669
6722
|
'<span>⏱ '+(wcState.lastGenStats.seconds >= 60 ? Math.floor(wcState.lastGenStats.seconds/60)+'m '+(wcState.lastGenStats.seconds%60)+'s' : wcState.lastGenStats.seconds+'s')+'</span>' +
|
|
@@ -6695,7 +6748,7 @@ function renderWebCraft(el) {
|
|
|
6695
6748
|
'<button onclick="wcTabFiles()" style="padding:8px 16px;background:'+(wcRightTab==='preview'?'transparent':'var(--bg3)')+';border:none;border-right:1px solid var(--border);color:'+(wcRightTab==='preview'?'var(--dim)':'var(--text)')+';font-size:11px;font-weight:600;cursor:pointer">📄 File</button>' +
|
|
6696
6749
|
'<button onclick="wcTabPreview()" style="padding:8px 16px;background:'+(wcRightTab==='preview'?'var(--bg3)':'transparent')+';border:none;color:'+(wcRightTab==='preview'?'var(--text)':'var(--dim)')+';font-size:11px;font-weight:600;cursor:pointer">🌐 Sandbox</button>' +
|
|
6697
6750
|
'</div>' +
|
|
6698
|
-
(wcRightTab === 'preview' ? wcSandboxPanelHtml() :
|
|
6751
|
+
(wcRightTab === 'preview' ? wcSandboxPanelHtml() : codeHtml) +
|
|
6699
6752
|
'</div>' +
|
|
6700
6753
|
'</div>' +
|
|
6701
6754
|
'</div>';
|
|
@@ -7879,6 +7932,8 @@ async function wcGenerate() {
|
|
|
7879
7932
|
|
|
7880
7933
|
var _nl = String.fromCharCode(10);
|
|
7881
7934
|
var sysPreamble = 'You are an expert full-stack engineer generating production-quality code.' + _nl + _nl + 'SECURITY RULES (non-negotiable):' + _nl + SECURITY_RULES + _nl + _nl + 'Project: ' + projName + _nl + 'Description: ' + desc + _nl + 'Enabled blocks: ' + blocksEnabled + _nl + _nl + 'Generate ONLY the file content requested. No explanations, no markdown code fences, no comments like "here is the file". Output raw file content only.';
|
|
7935
|
+
_wcLastFilePlan = filePlan;
|
|
7936
|
+
_wcLastSysPreamble = sysPreamble;
|
|
7882
7937
|
|
|
7883
7938
|
var _wcGenStartTime = Date.now();
|
|
7884
7939
|
var _wcTokIn = 0, _wcTokOut = 0;
|
|
@@ -7986,103 +8041,105 @@ async function wcGenerate() {
|
|
|
7986
8041
|
renderWebCraft(document.getElementById('content'));
|
|
7987
8042
|
}
|
|
7988
8043
|
|
|
7989
|
-
// ── Retry pass: regenerate files that failed ──────────────────────────────
|
|
7990
|
-
var failedFiles = wcState.generatedFiles.filter(function(f){ return f._error; });
|
|
7991
|
-
if (failedFiles.length > 0 && !(_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted)) {
|
|
7992
|
-
var retryPlan = filePlan.filter(function(fp){ return failedFiles.some(function(f){ return f.name === fp.name; }); });
|
|
7993
|
-
for (var ri = 0; ri < retryPlan.length; ri++) {
|
|
7994
|
-
var rfp = retryPlan[ri];
|
|
7995
|
-
wcUpdateGenOverlay(ri, retryPlan.length, 'Retry: ' + rfp.name);
|
|
7996
|
-
if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
|
|
7997
|
-
// Wait 3s before retry to let Liara recover
|
|
7998
|
-
await new Promise(function(resolve){ setTimeout(resolve, 3000); });
|
|
7999
|
-
try {
|
|
8000
|
-
var retryContent = await wcGenOneFile(rfp, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null);
|
|
8001
|
-
// Replace the error entry with the successful one
|
|
8002
|
-
for (var gi = 0; gi < wcState.generatedFiles.length; gi++) {
|
|
8003
|
-
if (wcState.generatedFiles[gi].name === rfp.name) {
|
|
8004
|
-
wcState.generatedFiles[gi] = { name: rfp.name, content: retryContent, lang: rfp.lang };
|
|
8005
|
-
break;
|
|
8006
|
-
}
|
|
8007
|
-
}
|
|
8008
|
-
renderWebCraft(document.getElementById('content'));
|
|
8009
|
-
} catch(re) {
|
|
8010
|
-
if (re && re.name === 'AbortError') break;
|
|
8011
|
-
// Keep as error — already in generatedFiles
|
|
8012
|
-
}
|
|
8013
|
-
}
|
|
8014
|
-
}
|
|
8015
|
-
|
|
8016
|
-
// ── Post-generation syntax scan ──────────────────────────────────────────
|
|
8017
|
-
// Zero LLM calls — pure structural check on every generated file
|
|
8018
|
-
// Files with syntax errors get _syntaxError set and are re-queued for retry
|
|
8019
|
-
var syntaxFailedNames = [];
|
|
8020
|
-
wcState.generatedFiles.forEach(function(f) {
|
|
8021
|
-
if (f._error) return; // already failed at LLM level
|
|
8022
|
-
var lang = f.lang || (f.name.endsWith('.css') ? 'css' : f.name.endsWith('.js') ? 'javascript' : f.name.endsWith('.html') ? 'html' : f.name.endsWith('.json') ? 'json' : 'text');
|
|
8023
|
-
var check = wcSyntaxCheck(f.content, lang);
|
|
8024
|
-
if (!check.ok) {
|
|
8025
|
-
f._syntaxError = check.reason;
|
|
8026
|
-
syntaxFailedNames.push(f.name);
|
|
8027
|
-
} else {
|
|
8028
|
-
delete f._syntaxError;
|
|
8029
|
-
}
|
|
8030
|
-
});
|
|
8031
|
-
|
|
8032
|
-
// Re-fix syntax-broken files — continue/patch, do NOT regenerate from scratch
|
|
8033
|
-
if (syntaxFailedNames.length > 0 && !(_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted)) {
|
|
8034
|
-
var syntaxRetryPlan = filePlan.filter(function(fp2){ return syntaxFailedNames.indexOf(fp2.name) !== -1; });
|
|
8035
|
-
for (var si2 = 0; si2 < syntaxRetryPlan.length; si2++) {
|
|
8036
|
-
var sfp = syntaxRetryPlan[si2];
|
|
8037
|
-
var brokenFile = wcState.generatedFiles.filter(function(f){ return f.name === sfp.name; })[0];
|
|
8038
|
-
if (!brokenFile) continue;
|
|
8039
|
-
wcUpdateGenOverlay(si2, syntaxRetryPlan.length, 'Fix: ' + sfp.name);
|
|
8040
|
-
if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
|
|
8041
|
-
await new Promise(function(resolve){ setTimeout(resolve, 1500); });
|
|
8042
|
-
try {
|
|
8043
|
-
var _nl3 = String.fromCharCode(10);
|
|
8044
|
-
// Build a targeted fix prompt — pass the broken file and ask only for the fix/completion
|
|
8045
|
-
var fixSys = sysPreamble + _nl3 + 'You are fixing a truncated or broken file. Output ONLY the corrected complete file content. No explanations, no markdown fences.';
|
|
8046
|
-
var fixUser = 'File: ' + sfp.name + _nl3 +
|
|
8047
|
-
'Syntax error: ' + (brokenFile._syntaxError || 'truncated') + _nl3 + _nl3 +
|
|
8048
|
-
'Current (broken) content:' + _nl3 + brokenFile.content + _nl3 + _nl3 +
|
|
8049
|
-
'Output the complete corrected file. If it was truncated, continue from where it stopped and output the FULL file from the beginning.';
|
|
8050
|
-
var fixedContent = await wcCallLLM(fixSys, fixUser, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null, sfp.lang);
|
|
8051
|
-
// Strip fences if model added them
|
|
8052
|
-
var _fence2 = String.fromCharCode(96,96,96);
|
|
8053
|
-
var fixLines = fixedContent.split(_nl3);
|
|
8054
|
-
if (fixLines.length > 0 && fixLines[0].indexOf(_fence2) === 0) fixLines.shift();
|
|
8055
|
-
if (fixLines.length > 0 && fixLines[fixLines.length-1].trim() === _fence2) fixLines.pop();
|
|
8056
|
-
fixedContent = fixLines.join(_nl3).trim();
|
|
8057
|
-
var fixCheck = wcSyntaxCheck(fixedContent, sfp.lang);
|
|
8058
|
-
for (var gi2 = 0; gi2 < wcState.generatedFiles.length; gi2++) {
|
|
8059
|
-
if (wcState.generatedFiles[gi2].name === sfp.name) {
|
|
8060
|
-
wcState.generatedFiles[gi2] = { name: sfp.name, content: fixedContent, lang: sfp.lang };
|
|
8061
|
-
if (!fixCheck.ok) wcState.generatedFiles[gi2]._syntaxError = fixCheck.reason;
|
|
8062
|
-
break;
|
|
8063
|
-
}
|
|
8064
|
-
}
|
|
8065
|
-
renderWebCraft(document.getElementById('content'));
|
|
8066
|
-
} catch(se) {
|
|
8067
|
-
if (se && se.name === 'AbortError') break;
|
|
8068
|
-
}
|
|
8069
|
-
}
|
|
8070
|
-
}
|
|
8071
|
-
|
|
8072
8044
|
if (_wcTimerInterval) { clearInterval(_wcTimerInterval); _wcTimerInterval = null; }
|
|
8073
8045
|
var _wcGenTotalTime = Math.floor((Date.now() - _wcGenStartTime) / 1000);
|
|
8074
8046
|
|
|
8075
8047
|
wcState.running = false;
|
|
8076
8048
|
_wcGenAbortCtrl = null;
|
|
8077
8049
|
_wcOverlayMinimized = false;
|
|
8078
|
-
// Store final stats for display after generation
|
|
8079
8050
|
wcState.lastGenStats = { tokIn: _wcTokIn, tokOut: _wcTokOut, seconds: _wcGenTotalTime, files: wcState.generatedFiles.length };
|
|
8080
8051
|
|
|
8081
|
-
// Auto-save
|
|
8052
|
+
// Auto-save
|
|
8082
8053
|
try {
|
|
8083
8054
|
await fetch(API + '/api/studio/webcraft/projects/save', {
|
|
8084
|
-
method: 'POST',
|
|
8085
|
-
|
|
8055
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
8056
|
+
body: JSON.stringify({ projectName: wcState.projectName, description: wcState.description, files: wcState.generatedFiles })
|
|
8057
|
+
});
|
|
8058
|
+
} catch(_) {}
|
|
8059
|
+
|
|
8060
|
+
renderWebCraft(document.getElementById('content'));
|
|
8061
|
+
|
|
8062
|
+
// Auto-repair: run immediately after generation completes
|
|
8063
|
+
await wcAutoRepair(filePlan, sysPreamble);
|
|
8064
|
+
}
|
|
8065
|
+
|
|
8066
|
+
// ── Auto-repair pass — fixes _error and _syntaxError files ────────────────
|
|
8067
|
+
// Called automatically after generation and available as manual button
|
|
8068
|
+
var _wcRepairRunning = false;
|
|
8069
|
+
async function wcAutoRepair(filePlan, sysPreamble) {
|
|
8070
|
+
if (_wcRepairRunning) return;
|
|
8071
|
+
// Collect broken files: LLM errors + syntax errors
|
|
8072
|
+
var toFix = wcState.generatedFiles.filter(function(f){ return f._error || f._syntaxError; });
|
|
8073
|
+
if (toFix.length === 0) return;
|
|
8074
|
+
|
|
8075
|
+
_wcRepairRunning = true;
|
|
8076
|
+
wcState.repairing = true;
|
|
8077
|
+
wcState.repairTotal = toFix.length;
|
|
8078
|
+
wcState.repairDone = 0;
|
|
8079
|
+
renderWebCraft(document.getElementById('content'));
|
|
8080
|
+
|
|
8081
|
+
// Build a map name→plan for prompt lookup
|
|
8082
|
+
var planMap = {};
|
|
8083
|
+
if (filePlan) filePlan.forEach(function(fp){ planMap[fp.name] = fp; });
|
|
8084
|
+
|
|
8085
|
+
var _nl3 = String.fromCharCode(10);
|
|
8086
|
+
var sysBase = sysPreamble || ('You are an expert full-stack engineer. Output ONLY the complete corrected file content. No explanations, no markdown fences.');
|
|
8087
|
+
|
|
8088
|
+
for (var ri = 0; ri < toFix.length; ri++) {
|
|
8089
|
+
var broken = toFix[ri];
|
|
8090
|
+
var plan = planMap[broken.name];
|
|
8091
|
+
wcState.repairDone = ri;
|
|
8092
|
+
wcState.repairCurrent = broken.name;
|
|
8093
|
+
renderWebCraft(document.getElementById('content'));
|
|
8094
|
+
|
|
8095
|
+
await new Promise(function(resolve){ setTimeout(resolve, 2000); });
|
|
8096
|
+
try {
|
|
8097
|
+
var fixSys = sysBase + _nl3 + 'You are fixing a broken or truncated file. Output ONLY the complete corrected file. No fences, no explanations.';
|
|
8098
|
+
var fixUser;
|
|
8099
|
+
if (broken._error) {
|
|
8100
|
+
// LLM failed entirely — regenerate from original prompt
|
|
8101
|
+
fixUser = plan
|
|
8102
|
+
? plan.prompt + _nl3 + _nl3 + 'File to generate: ' + broken.name
|
|
8103
|
+
: 'Regenerate the file: ' + broken.name;
|
|
8104
|
+
} else {
|
|
8105
|
+
// Syntax error — pass existing content + error for targeted fix
|
|
8106
|
+
fixUser = 'File: ' + broken.name + _nl3 +
|
|
8107
|
+
'Error: ' + (broken._syntaxError || 'truncated/incomplete') + _nl3 + _nl3 +
|
|
8108
|
+
'Current broken content (last 800 chars shown if long):' + _nl3 +
|
|
8109
|
+
(broken.content.length > 800 ? broken.content.slice(0, 400) + _nl3 + '...' + _nl3 + broken.content.slice(-400) : broken.content) + _nl3 + _nl3 +
|
|
8110
|
+
'Output the COMPLETE corrected file from the beginning.';
|
|
8111
|
+
}
|
|
8112
|
+
var fixed = await wcCallLLM(fixSys, fixUser, null, broken.lang || plan && plan.lang);
|
|
8113
|
+
var _fence3 = String.fromCharCode(96,96,96);
|
|
8114
|
+
var fixLines = fixed.split(_nl3);
|
|
8115
|
+
if (fixLines.length > 0 && fixLines[0].indexOf(_fence3) === 0) fixLines.shift();
|
|
8116
|
+
if (fixLines.length > 0 && fixLines[fixLines.length-1].trim() === _fence3) fixLines.pop();
|
|
8117
|
+
fixed = fixLines.join(_nl3).trim();
|
|
8118
|
+
var lang2 = broken.lang || (plan && plan.lang) || 'text';
|
|
8119
|
+
var check2 = wcSyntaxCheck(fixed, lang2);
|
|
8120
|
+
for (var gi3 = 0; gi3 < wcState.generatedFiles.length; gi3++) {
|
|
8121
|
+
if (wcState.generatedFiles[gi3].name === broken.name) {
|
|
8122
|
+
wcState.generatedFiles[gi3] = { name: broken.name, content: fixed, lang: lang2 };
|
|
8123
|
+
if (!check2.ok) wcState.generatedFiles[gi3]._syntaxError = check2.reason;
|
|
8124
|
+
break;
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
} catch(e) { /* keep as broken */ }
|
|
8128
|
+
|
|
8129
|
+
wcState.repairDone = ri + 1;
|
|
8130
|
+
renderWebCraft(document.getElementById('content'));
|
|
8131
|
+
}
|
|
8132
|
+
|
|
8133
|
+
_wcRepairRunning = false;
|
|
8134
|
+
wcState.repairing = false;
|
|
8135
|
+
wcState.repairTotal = 0;
|
|
8136
|
+
wcState.repairDone = 0;
|
|
8137
|
+
wcState.repairCurrent = '';
|
|
8138
|
+
|
|
8139
|
+
// Save after repair
|
|
8140
|
+
try {
|
|
8141
|
+
await fetch(API + '/api/studio/webcraft/projects/save', {
|
|
8142
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
8086
8143
|
body: JSON.stringify({ projectName: wcState.projectName, description: wcState.description, files: wcState.generatedFiles })
|
|
8087
8144
|
});
|
|
8088
8145
|
} catch(_) {}
|
|
@@ -8090,6 +8147,12 @@ async function wcGenerate() {
|
|
|
8090
8147
|
renderWebCraft(document.getElementById('content'));
|
|
8091
8148
|
}
|
|
8092
8149
|
|
|
8150
|
+
// Manual trigger for repair — called from "Correggi tutti" button
|
|
8151
|
+
function wcTriggerRepair() {
|
|
8152
|
+
if (_wcRepairRunning) return;
|
|
8153
|
+
wcAutoRepair(_wcLastFilePlan, _wcLastSysPreamble);
|
|
8154
|
+
}
|
|
8155
|
+
|
|
8093
8156
|
// Quick structural check — returns {ok, reason} without calling the LLM
|
|
8094
8157
|
// Reads only structure (braces, tags) — does NOT add content to any context
|
|
8095
8158
|
function wcSyntaxCheck(content, lang) {
|