nothumanallowed 13.5.65 → 13.5.67
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 +74 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.67",
|
|
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
|
@@ -4313,6 +4313,13 @@ module.exports = { get, set, del, exists };
|
|
|
4313
4313
|
[/require\(['"]\.\.\/\.\.\/config['"]\)/g, "{env:process.env}"],
|
|
4314
4314
|
[/require\(['"]\.\.\/config['"]\)/g, "{env:process.env}"],
|
|
4315
4315
|
[/require\(['"]\.\/config['"]\)/g, "{env:process.env}"],
|
|
4316
|
+
// rateLimiter: LLM sometimes creates a separate file instead of importing from security.js
|
|
4317
|
+
[/require\(['"]\.\.\/middleware\/rateLimiter['"]\)/g, "require('../middleware/security')"],
|
|
4318
|
+
[/require\(['"]\.\/middleware\/rateLimiter['"]\)/g, "require('./middleware/security')"],
|
|
4319
|
+
[/require\(['"]\.\.\/middleware\/rateLimit['"]\)/g, "require('../middleware/security')"],
|
|
4320
|
+
[/require\(['"]\.\/middleware\/rateLimit['"]\)/g, "require('./middleware/security')"],
|
|
4321
|
+
[/require\(['"]\.\.\/middleware\/limiter['"]\)/g, "require('../middleware/security')"],
|
|
4322
|
+
[/require\(['"]\.\/middleware\/limiter['"]\)/g, "require('./middleware/security')"],
|
|
4316
4323
|
];
|
|
4317
4324
|
function patchJsFiles(dir) {
|
|
4318
4325
|
if (!fs.existsSync(dir)) return;
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -6544,6 +6544,9 @@ var _wcDiffQueue = []; // [{file, before, after}] diffs from last agent ru
|
|
|
6544
6544
|
var _wcGrepOpen = false; // grep panel visible
|
|
6545
6545
|
var _wcGrepQuery = '';
|
|
6546
6546
|
var _wcGrepResults = [];
|
|
6547
|
+
var _wcOverlayMinimized = false; // overlay minimized by user click
|
|
6548
|
+
var _wcOverlayTimer = null; // inactivity timer to restore overlay
|
|
6549
|
+
var _wcGenAbortCtrl = null; // AbortController for generation stop
|
|
6547
6550
|
var _wcSyntaxResults = []; // [{file, ok, error}]
|
|
6548
6551
|
var _wcSnapshots = []; // [{ts, fileCount}]
|
|
6549
6552
|
// Skills state
|
|
@@ -6657,7 +6660,22 @@ function renderWebCraft(el) {
|
|
|
6657
6660
|
: '') +
|
|
6658
6661
|
'</div>' +
|
|
6659
6662
|
'<div data-wc-files style="position:relative;flex:1;min-width:0;background:var(--bg2);border:1px solid var(--border);border-radius:10px;display:flex;flex-direction:column;height:100%;overflow:hidden">' +
|
|
6660
|
-
(wcState.running ?
|
|
6663
|
+
(wcState.running ? (
|
|
6664
|
+
_wcOverlayMinimized
|
|
6665
|
+
// Minimized: small pill in bottom-right corner
|
|
6666
|
+
? '<div id="wcGenOverlay" onclick="wcOverlayRestore()" style="position:absolute;bottom:12px;right:12px;z-index:50;background:rgba(0,0,0,0.85);border:1px solid var(--green3);border-radius:20px;padding:5px 12px;display:flex;align-items:center;gap:7px;cursor:pointer;animation:wcBubbleIn .2s ease;backdrop-filter:blur(4px)">'
|
|
6667
|
+
+'<span style="font-size:16px;animation:wcRobotBob .9s ease-in-out infinite">🤖</span>'
|
|
6668
|
+
+'<span style="font-size:10px;color:var(--green);font-weight:700">Generando...</span>'
|
|
6669
|
+
+'<span style="display:flex;gap:3px">'+[0,1,2].map(function(_,idx){ return '<span style="width:4px;height:4px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.18)+'s"></span>'; }).join('')+'</span>'
|
|
6670
|
+
+'</div>'
|
|
6671
|
+
// Full overlay
|
|
6672
|
+
: '<div id="wcGenOverlay" onclick="wcOverlayMinimize()" title="Clicca per nascondere e navigare i file" style="position:absolute;inset:0;background:rgba(0,0,0,0.75);backdrop-filter:blur(4px);border-radius:10px;z-index:50;display:flex;flex-direction:column;align-items:center;justify-content:center;animation:wcBubbleIn .3s ease;cursor:pointer">'
|
|
6673
|
+
+'<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">🤖</div>'
|
|
6674
|
+
+'<div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Generazione in corso...</div>'
|
|
6675
|
+
+'<div style="font-size:10px;color:var(--dim);margin-top:4px">Clicca per navigare i file</div>'
|
|
6676
|
+
+'<div style="display:flex;gap:4px;margin-top:16px">'+[0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('')+'</div>'
|
|
6677
|
+
+'</div>'
|
|
6678
|
+
) : '') +
|
|
6661
6679
|
'<div style="display:flex;border-bottom:1px solid var(--border);flex-shrink:0">' +
|
|
6662
6680
|
'<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>' +
|
|
6663
6681
|
'<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>' +
|
|
@@ -7087,7 +7105,10 @@ function wcChatPanelHtml() {
|
|
|
7087
7105
|
'<input type="file" id="wcFileInput" multiple accept="image/*,.pdf" style="display:none" onchange="wcHandleFileAttach(this)">' +
|
|
7088
7106
|
'</label>' +
|
|
7089
7107
|
'<textarea id="wcChatInput" rows="4" placeholder="'+placeholder+'" '+(inputDisabled?'disabled':'')+' style="flex:1;padding:8px 10px;font-size:12px;border-radius:8px;border:1px solid var(--border2);background:var(--bg3);color:var(--text);resize:vertical;min-height:80px;line-height:1.5;font-family:inherit" onkeydown="wcChatKeydown(event)"></textarea>' +
|
|
7090
|
-
'<
|
|
7108
|
+
'<div style="display:flex;flex-direction:column;gap:5px;flex-shrink:0">' +
|
|
7109
|
+
'<button onclick="wcChatSend()" '+(inputDisabled?'disabled':'')+' style="padding:8px 14px;background:var(--green3);border:none;border-radius:8px;color:var(--bg);font-size:13px;font-weight:700;cursor:pointer;height:38px;white-space:nowrap">'+sendBtnLabel+'</button>' +
|
|
7110
|
+
(inputDisabled ? '<button onclick="wcStopAll()" style="padding:5px 10px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.4);border-radius:7px;color:#f87171;font-size:11px;font-weight:700;cursor:pointer;white-space:nowrap">■ Stop</button>' : '') +
|
|
7111
|
+
'</div>' +
|
|
7091
7112
|
'</div>' +
|
|
7092
7113
|
'</div>';
|
|
7093
7114
|
}
|
|
@@ -7096,6 +7117,17 @@ function wcChatKeydown(e) {
|
|
|
7096
7117
|
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); wcChatSend(); }
|
|
7097
7118
|
}
|
|
7098
7119
|
|
|
7120
|
+
function wcStopAll() {
|
|
7121
|
+
// Abort ongoing generation
|
|
7122
|
+
if (_wcGenAbortCtrl) { _wcGenAbortCtrl.abort(); _wcGenAbortCtrl = null; }
|
|
7123
|
+
wcState.running = false;
|
|
7124
|
+
wcChatRunning = false;
|
|
7125
|
+
_wcOverlayMinimized = false;
|
|
7126
|
+
if (_wcOverlayTimer) { clearTimeout(_wcOverlayTimer); _wcOverlayTimer = null; }
|
|
7127
|
+
wcChat.push({ role: 'system', text: '■ Generazione interrotta.' });
|
|
7128
|
+
renderWebCraft(document.getElementById('content'));
|
|
7129
|
+
}
|
|
7130
|
+
|
|
7099
7131
|
function wcRemoveAttachment(ai) {
|
|
7100
7132
|
wcChatAttachments.splice(ai, 1);
|
|
7101
7133
|
renderWebCraft(document.getElementById('content'));
|
|
@@ -7671,6 +7703,8 @@ async function wcGenerate() {
|
|
|
7671
7703
|
wcState.running = true;
|
|
7672
7704
|
wcState.generatedFiles = [];
|
|
7673
7705
|
wcState.activeFile = 0;
|
|
7706
|
+
_wcOverlayMinimized = false;
|
|
7707
|
+
_wcGenAbortCtrl = new AbortController();
|
|
7674
7708
|
renderWebCraft(document.getElementById('content'));
|
|
7675
7709
|
|
|
7676
7710
|
// Security rules always injected
|
|
@@ -7698,7 +7732,7 @@ async function wcGenerate() {
|
|
|
7698
7732
|
{ name: 'server/middleware/security.js', lang: 'javascript', prompt: 'Generate server/middleware/security.js: detect sandbox via isSandbox = !process.env.NODE_ENV || process.env.NODE_ENV === "development". Use helmet CSP: defaultSrc self, scriptSrc self unsafe-inline, styleSrc self unsafe-inline, imgSrc self data:, connectSrc self, objectSrc none. frameAncestors: if isSandbox use ["self", "http://127.0.0.1:*", "http://localhost:*"] else ["none"]. NO X-Frame-Options DENY (conflicts with frameAncestors). NO HSTS in sandbox (HTTP only). Referrer-Policy strict-origin-when-cross-origin. Add express-rate-limit for general routes (100/15min) and strict limiter for auth (5/15min). Export { applySecurityMiddleware, authLimiter }.' },
|
|
7699
7733
|
{ name: 'server/middleware/validate.js', lang: 'javascript', prompt: 'Generate server/middleware/validate.js using express-validator. Export handleValidationErrors middleware. Export auth field validators: registerValidator (fields: '+authFieldsDef+'), loginValidator (email + password).' },
|
|
7700
7734
|
{ name: 'server/services/email.js', lang: 'javascript', prompt: 'Generate server/services/email.js: Nodemailer transporter using SMTP from env. Function sendVerificationEmail(to, token, baseUrl): sends HTML email with verification link. Function sendPasswordResetEmail(to, token, baseUrl). Add SendGrid fallback (commented out, predisposed with transporter swap). Never expose credentials.' },
|
|
7701
|
-
{ name: 'server/routes/auth.js', lang: 'javascript', prompt: 'Generate server/routes/auth.js: POST /register (validate fields: '+authFieldsDef+', check duplicate email, bcrypt hash password cost 12, insert user, send verification email, return 201), POST /login (validate, check email verified, compare bcrypt, issue JWT access 15min + refresh 7d httpOnly cookie), POST /logout (clear refresh cookie), POST /refresh-token (validate refresh from httpOnly cookie, rotate token), GET /verify-email/:token (mark email verified). Use parameterized queries only. Apply authLimiter to register and login.' },
|
|
7735
|
+
{ name: 'server/routes/auth.js', lang: 'javascript', prompt: 'Generate server/routes/auth.js: POST /register (validate fields: '+authFieldsDef+', check duplicate email, bcrypt hash password cost 12, insert user, send verification email, return 201), POST /login (validate, check email verified, compare bcrypt, issue JWT access 15min + refresh 7d httpOnly cookie), POST /logout (clear refresh cookie), POST /refresh-token (validate refresh from httpOnly cookie, rotate token), GET /verify-email/:token (mark email verified). Use parameterized queries only. Import authLimiter EXACTLY like this: const { authLimiter } = require("../middleware/security"); — do NOT create or import from ../middleware/rateLimiter (that file does not exist). Apply authLimiter to register and login.' },
|
|
7702
7736
|
{ name: 'server/routes/api.js', lang: 'javascript', prompt: 'Generate server/routes/api.js: Express router with a verifyToken middleware (validates JWT Bearer). GET /api/me returns authenticated user profile (no password hash). GET /api/health returns {status: ok, timestamp}. Structure ready for adding more routes.' },
|
|
7703
7737
|
{ name: 'server/index.js', lang: 'javascript', prompt: 'Generate server/index.js: Express app entry point. Apply applySecurityMiddleware first. Then apply sentinelMiddleware (import from ./middleware/sentinel.js). Use CORS with env CORS_ORIGIN. Parse JSON body (limit 10kb). Mount /api/auth → auth.js, /api → api.js. Serve public/ as static. 404 handler and global error handler (never leak stack traces in production). Start on PORT from env.' },
|
|
7704
7738
|
{ name: 'db/migrations/001_init.sql', lang: 'sql', prompt: 'Generate PostgreSQL migration 001_init.sql: CREATE TABLE users with id UUID default gen_random_uuid(), fields for '+authFieldsDef+', email_verified BOOLEAN default false, verification_token VARCHAR, reset_token VARCHAR, reset_token_expires TIMESTAMPTZ, refresh_token_hash VARCHAR, created_at TIMESTAMPTZ default now(), updated_at TIMESTAMPTZ default now(). CREATE INDEX on email. CREATE TABLE refresh_tokens (id, user_id FK, token_hash, expires_at, created_at). Add updated_at trigger function.' },
|
|
@@ -7731,30 +7765,46 @@ async function wcGenerate() {
|
|
|
7731
7765
|
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.';
|
|
7732
7766
|
|
|
7733
7767
|
function wcUpdateGenOverlay(fi2, total, name) {
|
|
7768
|
+
if (_wcOverlayMinimized) return; // don't touch minimized pill
|
|
7734
7769
|
var ov = document.getElementById('wcGenOverlay');
|
|
7735
7770
|
if (!ov) return;
|
|
7736
7771
|
var pct = Math.round((fi2 / total) * 100);
|
|
7737
7772
|
ov.innerHTML =
|
|
7738
|
-
'<div style="
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7773
|
+
'<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">🤖</div>' +
|
|
7774
|
+
'<div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Generazione in corso...</div>' +
|
|
7775
|
+
'<div style="font-size:10px;color:var(--dim);margin-top:2px">Clicca per navigare i file</div>' +
|
|
7776
|
+
'<div style="font-size:11px;color:var(--dim);font-family:var(--mono);max-width:300px;text-align:center;word-break:break-all;margin-top:8px">'+wcEsc(name)+'</div>' +
|
|
7777
|
+
'<div style="width:220px;height:4px;background:rgba(255,255,255,0.1);border-radius:2px;overflow:hidden;margin-top:12px">' +
|
|
7778
|
+
'<div style="height:100%;width:'+pct+'%;background:var(--green);border-radius:2px;transition:width .4s ease;animation:wcBarPulse 1.5s ease-in-out infinite"></div>' +
|
|
7779
|
+
'</div>' +
|
|
7780
|
+
'<div style="font-size:10px;color:var(--dim);margin-top:6px">'+fi2+' / '+total+' file</div>' +
|
|
7781
|
+
'<div style="display:flex;gap:4px;margin-top:10px">'+[0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('')+'</div>';
|
|
7782
|
+
}
|
|
7783
|
+
|
|
7784
|
+
function wcOverlayMinimize() {
|
|
7785
|
+
_wcOverlayMinimized = true;
|
|
7786
|
+
renderWebCraft(document.getElementById('content'));
|
|
7787
|
+
// Restore after 10s of inactivity
|
|
7788
|
+
if (_wcOverlayTimer) clearTimeout(_wcOverlayTimer);
|
|
7789
|
+
_wcOverlayTimer = setTimeout(function() {
|
|
7790
|
+
if (wcState.running) { _wcOverlayMinimized = false; renderWebCraft(document.getElementById('content')); }
|
|
7791
|
+
}, 10000);
|
|
7792
|
+
}
|
|
7793
|
+
|
|
7794
|
+
function wcOverlayRestore() {
|
|
7795
|
+
if (_wcOverlayTimer) { clearTimeout(_wcOverlayTimer); _wcOverlayTimer = null; }
|
|
7796
|
+
_wcOverlayMinimized = false;
|
|
7797
|
+
renderWebCraft(document.getElementById('content'));
|
|
7750
7798
|
}
|
|
7751
7799
|
|
|
7752
7800
|
for (var fi = 0; fi < filePlan.length; fi++) {
|
|
7753
7801
|
var fp = filePlan[fi];
|
|
7754
7802
|
wcUpdateGenOverlay(fi, filePlan.length, fp.name);
|
|
7803
|
+
// Check if aborted
|
|
7804
|
+
if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
|
|
7755
7805
|
try {
|
|
7756
7806
|
var _nl2 = String.fromCharCode(10);
|
|
7757
|
-
var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name);
|
|
7807
|
+
var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null);
|
|
7758
7808
|
// Strip markdown code fences if model added them anyway
|
|
7759
7809
|
var _fence = String.fromCharCode(96,96,96);
|
|
7760
7810
|
var wcLines = content.split(_nl2);
|
|
@@ -7765,11 +7815,14 @@ async function wcGenerate() {
|
|
|
7765
7815
|
if (fi === 0) wcState.activeFile = 0;
|
|
7766
7816
|
renderWebCraft(document.getElementById('content'));
|
|
7767
7817
|
} catch(e) {
|
|
7818
|
+
if (e && e.name === 'AbortError') break;
|
|
7768
7819
|
wcState.generatedFiles.push({ name: fp.name, content: '// Error generating this file: ' + e.message, lang: fp.lang });
|
|
7769
7820
|
}
|
|
7770
7821
|
}
|
|
7771
7822
|
|
|
7772
7823
|
wcState.running = false;
|
|
7824
|
+
_wcGenAbortCtrl = null;
|
|
7825
|
+
_wcOverlayMinimized = false;
|
|
7773
7826
|
|
|
7774
7827
|
// Auto-save project to ~/.nha/webcraft/<projectName>/
|
|
7775
7828
|
try {
|
|
@@ -7783,12 +7836,14 @@ async function wcGenerate() {
|
|
|
7783
7836
|
renderWebCraft(document.getElementById('content'));
|
|
7784
7837
|
}
|
|
7785
7838
|
|
|
7786
|
-
async function wcCallLLM(sys, user) {
|
|
7787
|
-
var
|
|
7839
|
+
async function wcCallLLM(sys, user, signal) {
|
|
7840
|
+
var fetchOpts = {
|
|
7788
7841
|
method: 'POST',
|
|
7789
7842
|
headers: {'Content-Type':'application/json'},
|
|
7790
7843
|
body: JSON.stringify({system: sys, user: user, max_tokens: 4096})
|
|
7791
|
-
}
|
|
7844
|
+
};
|
|
7845
|
+
if (signal) fetchOpts.signal = signal;
|
|
7846
|
+
var r = await fetch(API + '/api/studio/webcraft', fetchOpts);
|
|
7792
7847
|
if (!r.ok) throw new Error('LLM error ' + r.status);
|
|
7793
7848
|
var d = await r.json();
|
|
7794
7849
|
return (d && (d.text || d.content || d.result)) || '';
|