nothumanallowed 16.0.45 → 16.0.46
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/constants.mjs +1 -1
- package/src/server/routes/webcraft.mjs +58 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.46",
|
|
4
4
|
"description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Free tier built-in (Liara), no API key required. Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
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 = '16.0.
|
|
8
|
+
export const VERSION = '16.0.46';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -233,12 +233,24 @@ class SandboxManager {
|
|
|
233
233
|
// Detects "incomplete styling" (LLM truncated CSS generation) and calls
|
|
234
234
|
// the LLM automatically to extend the CSS file with rules for the missing
|
|
235
235
|
// HTML selectors. NO user intervention required.
|
|
236
|
+
// Iterates up to 2 times to handle large projects where a single extend
|
|
237
|
+
// might not cover all selectors (e.g. 200+ missing selectors).
|
|
236
238
|
try {
|
|
237
239
|
const projectName = path.basename(projectDir);
|
|
238
240
|
const cfg = loadConfig();
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
const maxPasses = 2;
|
|
242
|
+
let totalCovered = 0;
|
|
243
|
+
for (let pass = 1; pass <= maxPasses; pass++) {
|
|
244
|
+
const styleResult = await _autoExtendStylesIfNeeded(projectName, cfg, emit, { minCoverage: 0.85 });
|
|
245
|
+
if (!styleResult.extended) {
|
|
246
|
+
if (styleResult.reason === 'coverage acceptable') break;
|
|
247
|
+
// LLM failed or skipped — don't loop on a broken provider
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
const newlyCovered = (styleResult.missingBefore || 0) - (styleResult.missingAfter || 0);
|
|
251
|
+
totalCovered += newlyCovered;
|
|
252
|
+
emit({ type: 'status', msg: `Pass ${pass}/${maxPasses}: ${styleResult.file} extended — ${newlyCovered} new selectors covered (total ${totalCovered}).` });
|
|
253
|
+
if ((styleResult.coverageAfter || 0) >= 0.85) break;
|
|
242
254
|
}
|
|
243
255
|
} catch (e) {
|
|
244
256
|
emit({ type: 'warn', msg: `Auto-extend styles failed: ${(e.message || e).slice(0, 200)}` });
|
|
@@ -4254,27 +4266,57 @@ export async function _autoExtendStylesIfNeeded(projectName, config, emit, opts)
|
|
|
4254
4266
|
} catch {}
|
|
4255
4267
|
}
|
|
4256
4268
|
|
|
4257
|
-
const sys =
|
|
4269
|
+
const sys = `You are an expert frontend designer producing PRODUCTION-QUALITY CSS.
|
|
4270
|
+
|
|
4271
|
+
DESIGN REQUIREMENTS (NON-NEGOTIABLE):
|
|
4272
|
+
- WCAG AA contrast: text-on-background ratio >= 4.5:1. NO washed-out pastels for text. Body text must be near-black on light bg, or near-white on dark bg.
|
|
4273
|
+
- Use VIBRANT accent colors with sufficient saturation (HSL S >= 60%, L between 35-65% for accents).
|
|
4274
|
+
- Cover EVERY selector listed — including footer, header, nav, hero, sections, cards, buttons, forms, modals, tooltips.
|
|
4275
|
+
- Use modern CSS: flex/grid layouts, custom properties for colors, smooth transitions (200-300ms), subtle shadows.
|
|
4276
|
+
|
|
4277
|
+
OUTPUT: ONLY the complete extended CSS file content. No markdown fences, no explanations, no preamble. The output will be written directly to disk.`;
|
|
4258
4278
|
const user =
|
|
4259
4279
|
`Extend this CSS file: \`${targetRel}\`\n\n` +
|
|
4260
4280
|
`Current CSS (${target.size} bytes, ${analysis.cssRuleCount} rules):\n\`\`\`css\n${target.content.slice(0, 6000)}\n\`\`\`\n\n` +
|
|
4261
|
-
`
|
|
4281
|
+
`ALL missing selectors (${analysis.missing.length} — cover every single one):\n${analysis.missing.join(', ')}\n\n` +
|
|
4262
4282
|
`HTML files for context:\n${htmlSample}\n\n` +
|
|
4263
|
-
`Output the COMPLETE extended CSS file
|
|
4264
|
-
`- img { max-width: 100%; height: auto; object-fit: cover; }\n` +
|
|
4265
|
-
`-
|
|
4266
|
-
`-
|
|
4267
|
-
`-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4283
|
+
`Output the COMPLETE extended CSS file. Required additions:\n` +
|
|
4284
|
+
`- img { max-width: 100%; height: auto; object-fit: cover; display: block; }\n` +
|
|
4285
|
+
`- Footer, header, nav with proper layout and visible styling (NOT transparent backgrounds with low-contrast text)\n` +
|
|
4286
|
+
`- Rules for EVERY one of the ${analysis.missing.length} missing selectors above\n` +
|
|
4287
|
+
`- Responsive breakpoints at 1024px, 768px, 480px (mobile-first)\n` +
|
|
4288
|
+
`- Hover/focus/transition states for buttons, links, cards\n` +
|
|
4289
|
+
`- Color contrast must pass WCAG AA: text-on-bg >= 4.5:1`;
|
|
4290
|
+
|
|
4291
|
+
if (emit) emit({ type: 'status', msg: `CSS coverage ${(analysis.coverage * 100).toFixed(0)}% (${analysis.missing.length} selectors missing). Auto-extending ${targetRel} via LLM (timeout 60s)...` });
|
|
4292
|
+
|
|
4293
|
+
// Call LLM with timeout + progress heartbeat. Otherwise a slow/stuck Liara
|
|
4294
|
+
// leaves the user staring at "Auto-extending..." forever with no feedback.
|
|
4271
4295
|
let body = '';
|
|
4296
|
+
let lastChunkAt = Date.now();
|
|
4297
|
+
const startedAt = Date.now();
|
|
4298
|
+
const timeoutMs = 60_000;
|
|
4299
|
+
const heartbeatInterval = setInterval(() => {
|
|
4300
|
+
if (!emit) return;
|
|
4301
|
+
const elapsed = ((Date.now() - startedAt) / 1000).toFixed(0);
|
|
4302
|
+
const sinceLast = ((Date.now() - lastChunkAt) / 1000).toFixed(0);
|
|
4303
|
+
emit({ type: 'status', msg: `LLM extend: ${elapsed}s elapsed, ${body.length} bytes received (${sinceLast}s since last chunk)` });
|
|
4304
|
+
}, 5_000);
|
|
4305
|
+
|
|
4272
4306
|
try {
|
|
4273
|
-
await
|
|
4307
|
+
await Promise.race([
|
|
4308
|
+
callLLMStream(config, sys, user, (chunk) => {
|
|
4309
|
+
body += chunk;
|
|
4310
|
+
lastChunkAt = Date.now();
|
|
4311
|
+
}, { max_tokens: 8192 }),
|
|
4312
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('LLM timeout after ' + (timeoutMs / 1000) + 's')), timeoutMs)),
|
|
4313
|
+
]);
|
|
4274
4314
|
} catch (e) {
|
|
4275
|
-
|
|
4276
|
-
|
|
4315
|
+
clearInterval(heartbeatInterval);
|
|
4316
|
+
if (emit) emit({ type: 'warn', msg: `CSS extend failed: ${(e.message || e).slice(0, 200)}. Sandbox continues with current CSS — open chat to extend manually.` });
|
|
4317
|
+
return { extended: false, reason: 'llm_failed', error: e.message, partialBytes: body.length };
|
|
4277
4318
|
}
|
|
4319
|
+
clearInterval(heartbeatInterval);
|
|
4278
4320
|
|
|
4279
4321
|
// Strip markdown fences
|
|
4280
4322
|
body = body.replace(/^```[a-zA-Z]*\n?/m, '').replace(/\n?```\s*$/m, '').trim();
|