nothumanallowed 13.5.79 → 13.5.81
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 +7 -0
- package/src/services/web-ui.mjs +44 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.81",
|
|
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
|
@@ -3892,6 +3892,13 @@ ${completedHeadings ? `## SECTIONS ALREADY WRITTEN (headings only):\n${completed
|
|
|
3892
3892
|
if (pathname.startsWith('/api/studio/webcraft/projects/') && method === 'DELETE') {
|
|
3893
3893
|
const projName = decodeURIComponent(pathname.replace('/api/studio/webcraft/projects/', '')).replace(/[^a-zA-Z0-9_-]/g, '');
|
|
3894
3894
|
if (!projName) { sendJSON(res, 400, { error: 'invalid name' }); return; }
|
|
3895
|
+
// Kill sandbox process if it belongs to this project
|
|
3896
|
+
if (global._wcSandboxProc && global._wcSandboxDir && global._wcSandboxDir.includes(projName)) {
|
|
3897
|
+
try { global._wcSandboxProc.kill('SIGTERM'); } catch(_) {}
|
|
3898
|
+
global._wcSandboxProc = null;
|
|
3899
|
+
global._wcSandboxPort = null;
|
|
3900
|
+
global._wcSandboxDir = null;
|
|
3901
|
+
}
|
|
3895
3902
|
const projDir = path.join(os.homedir(), '.nha', 'webcraft', projName);
|
|
3896
3903
|
if (fs.existsSync(projDir)) fs.rmSync(projDir, { recursive: true, force: true });
|
|
3897
3904
|
sendJSON(res, 200, { ok: true });
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -7890,7 +7890,7 @@ async function wcGenerate() {
|
|
|
7890
7890
|
// Helper: generate one file, returns {ok, content} or {ok:false, err}
|
|
7891
7891
|
async function wcGenOneFile(fp, signal) {
|
|
7892
7892
|
var _nl2 = String.fromCharCode(10);
|
|
7893
|
-
var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, signal);
|
|
7893
|
+
var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, signal, fp.lang);
|
|
7894
7894
|
var _fence = String.fromCharCode(96,96,96);
|
|
7895
7895
|
var wcLines = content.split(_nl2);
|
|
7896
7896
|
if (wcLines.length > 0 && wcLines[0].indexOf(_fence) === 0) wcLines.shift();
|
|
@@ -7958,14 +7958,38 @@ async function wcGenerate() {
|
|
|
7958
7958
|
renderWebCraft(document.getElementById('content'));
|
|
7959
7959
|
}
|
|
7960
7960
|
|
|
7961
|
-
|
|
7961
|
+
// Returns true if content looks truncated (unbalanced braces or ends mid-rule)
|
|
7962
|
+
function wcIsTruncated(content, lang) {
|
|
7963
|
+
if (!content || content.length < 100) return false;
|
|
7964
|
+
var trimmed = content.trimEnd();
|
|
7965
|
+
// CSS/SCSS: count { vs } — if open > closed, truncated
|
|
7966
|
+
if (lang === 'css' || lang === 'scss') {
|
|
7967
|
+
var open = 0, close = 0;
|
|
7968
|
+
for (var ci = 0; ci < trimmed.length; ci++) {
|
|
7969
|
+
if (trimmed[ci] === '{') open++;
|
|
7970
|
+
else if (trimmed[ci] === '}') close++;
|
|
7971
|
+
}
|
|
7972
|
+
return open > close;
|
|
7973
|
+
}
|
|
7974
|
+
// JS: ends without closing brace/semicolon — rough heuristic
|
|
7975
|
+
if (lang === 'javascript') {
|
|
7976
|
+
var last = trimmed[trimmed.length - 1];
|
|
7977
|
+
return last !== '}' && last !== ';' && last !== ')';
|
|
7978
|
+
}
|
|
7979
|
+
// HTML: doesn't end with closing tag
|
|
7980
|
+
if (lang === 'html') {
|
|
7981
|
+
return trimmed.slice(-7).indexOf('</html>') === -1 && trimmed.slice(-8).indexOf('</body>') === -1;
|
|
7982
|
+
}
|
|
7983
|
+
return false;
|
|
7984
|
+
}
|
|
7985
|
+
|
|
7986
|
+
async function wcCallLLMRaw(sys, user, signal) {
|
|
7962
7987
|
var fetchOpts = {
|
|
7963
7988
|
method: 'POST',
|
|
7964
7989
|
headers: {'Content-Type':'application/json'},
|
|
7965
7990
|
body: JSON.stringify({system: sys, user: user, max_tokens: 4096})
|
|
7966
7991
|
};
|
|
7967
7992
|
if (signal) fetchOpts.signal = signal;
|
|
7968
|
-
// Retry up to 2 times on 5xx errors (Liara may be temporarily overloaded)
|
|
7969
7993
|
for (var attempt = 0; attempt < 3; attempt++) {
|
|
7970
7994
|
if (signal && signal.aborted) throw new DOMException('Aborted', 'AbortError');
|
|
7971
7995
|
var r = await fetch(API + '/api/studio/webcraft', fetchOpts);
|
|
@@ -7978,11 +8002,27 @@ async function wcCallLLM(sys, user, signal) {
|
|
|
7978
8002
|
try { var eb = await r.json(); errBody = eb.error || ''; } catch(_) {}
|
|
7979
8003
|
throw new Error('LLM error ' + r.status + (errBody ? ': ' + errBody : ''));
|
|
7980
8004
|
}
|
|
7981
|
-
// 5xx — wait 2s then retry
|
|
7982
8005
|
await new Promise(function(resolve) { setTimeout(resolve, 2000); });
|
|
7983
8006
|
}
|
|
7984
8007
|
}
|
|
7985
8008
|
|
|
8009
|
+
async function wcCallLLM(sys, user, signal, lang) {
|
|
8010
|
+
var content = await wcCallLLMRaw(sys, user, signal);
|
|
8011
|
+
// Continuation loop: if response is truncated, ask model to continue
|
|
8012
|
+
var maxContinuations = 2;
|
|
8013
|
+
for (var ci = 0; ci < maxContinuations; ci++) {
|
|
8014
|
+
if (!wcIsTruncated(content, lang || 'text')) break;
|
|
8015
|
+
if (signal && signal.aborted) break;
|
|
8016
|
+
var continuePrompt = 'Continue generating the file EXACTLY from where you stopped. Do not repeat anything already written. Output ONLY the remaining code, starting from the next character after where you stopped.' +
|
|
8017
|
+
String.fromCharCode(10) + String.fromCharCode(10) + 'The file so far ends with:' +
|
|
8018
|
+
String.fromCharCode(10) + content.slice(-300);
|
|
8019
|
+
var continuation = await wcCallLLMRaw(sys, continuePrompt, signal);
|
|
8020
|
+
if (!continuation || continuation.trim().length < 5) break;
|
|
8021
|
+
content = content + String.fromCharCode(10) + continuation;
|
|
8022
|
+
}
|
|
8023
|
+
return content;
|
|
8024
|
+
}
|
|
8025
|
+
|
|
7986
8026
|
function wcSandboxPanelHtml() {
|
|
7987
8027
|
var sb = wcState.sandbox;
|
|
7988
8028
|
if (!wcState.generatedFiles.length) {
|