nothumanallowed 16.0.35 → 16.0.37

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "16.0.35",
3
+ "version": "16.0.37",
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.35';
8
+ export const VERSION = '16.0.37';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -218,6 +218,17 @@ class SandboxManager {
218
218
  emit({ type: 'warn', msg: `Pre-flight repair: ${repaired.length} file${repaired.length === 1 ? '' : 's'} quarantined (corrupted content) → ${repaired.join(', ')}. Re-generate from chat to restore them.` });
219
219
  }
220
220
 
221
+ // Pre-flight: create missing data dirs/files referenced by code.
222
+ // LLMs frequently generate `fs.writeFile('data/users.json', ...)` without
223
+ // creating data/ first → ENOENT crash on boot. Scan code for these
224
+ // references and seed empty placeholders BEFORE the sandbox starts.
225
+ try {
226
+ const dataFiles = _detectMissingDataFiles(projectDir);
227
+ if (dataFiles.length > 0) {
228
+ emit({ type: 'status', msg: `Pre-flight: seeded ${dataFiles.length} data file${dataFiles.length === 1 ? '' : 's'} → ${dataFiles.slice(0, 5).join(', ')}${dataFiles.length > 5 ? '...' : ''}` });
229
+ }
230
+ } catch {}
231
+
221
232
  // ── Phase 2: Dependencies (pre-scan + batch install) ──────────────────
222
233
  // Pre-scan the project source files for require()/import statements and
223
234
  // diff against package.json + node_modules. Install everything missing in
@@ -454,6 +465,36 @@ class SandboxManager {
454
465
  return this.start(projectName, projectDir, emit, _attempt + 1);
455
466
  }
456
467
  }
468
+ }
469
+
470
+ // ── Tier 1b: ENOENT on file write → create missing path + retry ──────
471
+ // Deterministic. LLM SaaS code often writes to data/users.json without
472
+ // mkdir -p data/ first → ENOENT. We detect, create the dir + empty
473
+ // placeholder JSON, and retry. Zero LLM call needed.
474
+ const enoentMatch = stderrBuf.match(/ENOENT[^']*open\s+['"]([^'"]+)['"]/);
475
+ if (enoentMatch && _attempt < MAX_RETRIES) {
476
+ const missingPath = enoentMatch[1];
477
+ // Only auto-create if path is inside the project
478
+ const projectAbs = path.resolve(projectDir);
479
+ const missingAbs = path.resolve(missingPath);
480
+ if (missingAbs.startsWith(projectAbs)) {
481
+ emit({ type: 'phase', phase: 'autofix', msg: `ENOENT on ${missingPath} — creating directory + empty placeholder...` });
482
+ try {
483
+ ensureDir(path.dirname(missingAbs));
484
+ if (!fs.existsSync(missingAbs)) {
485
+ const ext = path.extname(missingAbs).toLowerCase();
486
+ let stub = '';
487
+ if (ext === '.json') stub = /users|posts|items|list|todos|comments|orders|products/i.test(missingPath) ? '[]' : '{}';
488
+ else if (ext === '.sqlite' || ext === '.db') { /* skip binary */ }
489
+ else stub = '';
490
+ if (ext !== '.sqlite' && ext !== '.db') fs.writeFileSync(missingAbs, stub, 'utf-8');
491
+ }
492
+ emit({ type: 'status', msg: `Created ${missingPath} — retrying (attempt ${_attempt + 1}/${MAX_RETRIES})...` });
493
+ return this.start(projectName, projectDir, emit, _attempt + 1);
494
+ } catch (e) {
495
+ emit({ type: 'warn', msg: `Failed to create ${missingPath}: ${e.message.slice(0, 200)}` });
496
+ }
497
+ }
457
498
  } else if (missingModules.length > 0 && uniqueMissing.length === 0) {
458
499
  // All missing modules are shimmable in THIS version of the CLI. If we
459
500
  // reached this branch, the user has an OLDER CLI installed that doesn't
@@ -3383,6 +3424,20 @@ ${original.slice(0, 12_000)}`;
3383
3424
  } catch (e) { console.error('[scan] CRASH:', e); sendError(res, 500, e.message); }
3384
3425
  });
3385
3426
 
3427
+ // ── Deterministic auto-repair (zero LLM, pure code) ────────────────────────
3428
+ // Handles the common bug classes that the LLM gets wrong:
3429
+ // 1. Mismatched/unclosed HTML tags → balance via tag stack
3430
+ // 2. Referenced files not found → create empty placeholders
3431
+ // No tool calling, no streaming, no LLM. Synchronous fixes.
3432
+ router.post('/api/studio/webcraft/auto-repair', async (req, res) => {
3433
+ try {
3434
+ const { projectName } = await parseBody(req);
3435
+ if (!projectName) return sendError(res, 400, 'projectName required');
3436
+ const result = autoRepairProject(projectName);
3437
+ sendJSON(res, 200, result);
3438
+ } catch (e) { sendError(res, 500, e.message); }
3439
+ });
3440
+
3386
3441
  // ── Syntax check ──────────────────────────────────────────────────────────
3387
3442
  router.post('/api/studio/webcraft/syntax-check', async (req, res) => {
3388
3443
  try {
@@ -3411,6 +3466,261 @@ function _safeName(name) {
3411
3466
  * This extracts "op", "path", "old", "new", "content", "query", "cmd" etc. by finding
3412
3467
  * the key-value boundaries manually.
3413
3468
  */
3469
+ // ─────────────────────────────────────────────────────────────────────────────
3470
+ // DETERMINISTIC AUTO-REPAIR
3471
+ // Fixes common bug classes (mismatched HTML tags, missing CSS/JS files) using
3472
+ // pure code — NO LLM call. The LLM-based "Fix" button is fragile when the
3473
+ // provider doesn't support native tool calling; this deterministic pass runs
3474
+ // first and resolves 80% of common project errors instantly.
3475
+ // ─────────────────────────────────────────────────────────────────────────────
3476
+
3477
+ const _HTML_VOID = new Set([
3478
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta',
3479
+ 'param', 'source', 'track', 'wbr',
3480
+ ]);
3481
+
3482
+ /**
3483
+ * Balance HTML tags in `html` by tracking open/close via a pushdown stack.
3484
+ * Returns { fixed, balanced, edits } where:
3485
+ * - fixed: the corrected HTML string
3486
+ * - balanced: true if tags were already balanced or fixable, false if too broken
3487
+ * - edits: list of human-readable changes (for logging)
3488
+ */
3489
+ export function _balanceHtmlTags(html) {
3490
+ const edits = [];
3491
+ // Strip comments and scripts/styles to avoid false matches in their content
3492
+ const placeholders = [];
3493
+ let work = html
3494
+ .replace(/<!--[\s\S]*?-->/g, (m) => { placeholders.push(m); return `__NHA_PH_${placeholders.length - 1}__`; })
3495
+ .replace(/<(script|style)([^>]*)>([\s\S]*?)<\/\1>/gi, (m) => { placeholders.push(m); return `__NHA_PH_${placeholders.length - 1}__`; });
3496
+
3497
+ const tagRe = /<\/?([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*?>/g;
3498
+ const stack = [];
3499
+ let outStr = '';
3500
+ let lastIdx = 0;
3501
+ let match;
3502
+
3503
+ while ((match = tagRe.exec(work)) !== null) {
3504
+ const tag = match[0];
3505
+ const name = match[1].toLowerCase();
3506
+ const isClose = tag.startsWith('</');
3507
+ const isSelfClose = tag.endsWith('/>') || _HTML_VOID.has(name);
3508
+
3509
+ outStr += work.slice(lastIdx, match.index);
3510
+
3511
+ if (isClose) {
3512
+ // Find matching open in stack
3513
+ let depth = stack.length - 1;
3514
+ let foundAt = -1;
3515
+ while (depth >= 0) {
3516
+ if (stack[depth].name === name) { foundAt = depth; break; }
3517
+ depth--;
3518
+ }
3519
+ if (foundAt === -1) {
3520
+ // Stray close — drop it
3521
+ edits.push(`Removed stray </${name}>`);
3522
+ // Skip writing this tag
3523
+ lastIdx = match.index + tag.length;
3524
+ continue;
3525
+ }
3526
+ // Auto-close anything above the match
3527
+ while (stack.length - 1 > foundAt) {
3528
+ const top = stack.pop();
3529
+ outStr += `</${top.name}>`;
3530
+ edits.push(`Auto-closed <${top.name}> before </${name}>`);
3531
+ }
3532
+ stack.pop();
3533
+ outStr += tag;
3534
+ } else if (isSelfClose) {
3535
+ outStr += tag;
3536
+ } else {
3537
+ stack.push({ name, idx: match.index });
3538
+ outStr += tag;
3539
+ }
3540
+ lastIdx = match.index + tag.length;
3541
+ }
3542
+ outStr += work.slice(lastIdx);
3543
+
3544
+ // Close any remaining open tags at the very end
3545
+ while (stack.length > 0) {
3546
+ const top = stack.pop();
3547
+ // Insert closing tags before </body> or </html> if present, else at end
3548
+ const bodyClose = outStr.lastIndexOf('</body>');
3549
+ const htmlClose = outStr.lastIndexOf('</html>');
3550
+ let insertAt = outStr.length;
3551
+ if (bodyClose !== -1 && top.name !== 'body' && top.name !== 'html') insertAt = bodyClose;
3552
+ else if (htmlClose !== -1 && top.name !== 'html') insertAt = htmlClose;
3553
+ outStr = outStr.slice(0, insertAt) + `</${top.name}>` + outStr.slice(insertAt);
3554
+ edits.push(`Auto-closed <${top.name}> at end of document`);
3555
+ }
3556
+
3557
+ // Restore placeholders
3558
+ const fixed = outStr.replace(/__NHA_PH_(\d+)__/g, (_, i) => placeholders[+i] || '');
3559
+ return { fixed, balanced: true, edits };
3560
+ }
3561
+
3562
+ /**
3563
+ * Extract <link href="..."> and <script src="..."> + <img src="..."> targets
3564
+ * from HTML. Returns relative paths that point inside the project.
3565
+ */
3566
+ function _extractHtmlAssetRefs(html) {
3567
+ const refs = [];
3568
+ const linkRe = /<link\b[^>]*\bhref\s*=\s*["']([^"']+)["'][^>]*>/gi;
3569
+ const scriptRe = /<script\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/gi;
3570
+ let m;
3571
+ while ((m = linkRe.exec(html)) !== null) refs.push({ kind: 'css', href: m[1] });
3572
+ while ((m = scriptRe.exec(html)) !== null) refs.push({ kind: 'js', href: m[1] });
3573
+ return refs;
3574
+ }
3575
+
3576
+ function _normalizeAssetPath(href, htmlRelPath) {
3577
+ // Strip query/hash
3578
+ let p = href.replace(/[?#].*$/, '');
3579
+ // Skip external (http://, https://, //, data:)
3580
+ if (/^(?:https?:)?\/\//.test(p) || p.startsWith('data:') || p.startsWith('//')) return null;
3581
+ // Absolute paths starting with / are project-root-relative
3582
+ if (p.startsWith('/')) return p.slice(1);
3583
+ // Relative paths — resolve against the HTML file's directory
3584
+ const htmlDir = path.dirname(htmlRelPath);
3585
+ return path.posix.normalize(path.posix.join(htmlDir, p));
3586
+ }
3587
+
3588
+ function _placeholderContent(kind, refPath) {
3589
+ if (kind === 'css') {
3590
+ return `/* nha-webcraft: auto-created placeholder for ${refPath}\n The HTML referenced this file but it didn't exist. This is a\n minimal stub to keep the sandbox bootable. Add real styles via chat. */\n\n/* base reset */\n* { box-sizing: border-box; }\nbody { margin: 0; font-family: -apple-system, BlinkMacSystemFont, system-ui, sans-serif; }\n`;
3591
+ }
3592
+ if (kind === 'js') {
3593
+ return `// nha-webcraft: auto-created placeholder for ${refPath}\n// The HTML referenced this file but it didn't exist. This is a\n// minimal stub to keep the sandbox bootable. Add real logic via chat.\nconsole.log('[${refPath}] placeholder loaded');\n`;
3594
+ }
3595
+ return '';
3596
+ }
3597
+
3598
+ /**
3599
+ * Scan all .js/.mjs/.ts files for filesystem paths referenced in string
3600
+ * literals (typically used for file-based storage by LLM-generated SaaS code:
3601
+ * fs.writeFile('data/users.json', ...), fs.readFile('db/posts.json'), etc).
3602
+ * Creates missing directories + empty JSON placeholders so the app can boot
3603
+ * instead of crashing with ENOENT on first write.
3604
+ */
3605
+ export function _detectMissingDataFiles(projectDir) {
3606
+ const created = [];
3607
+ const exts = new Set(['.js', '.mjs', '.cjs', '.ts']);
3608
+ const skipDirs = new Set(['node_modules', '.git', '.nha-shims', 'dist', 'build', '.next', 'public']);
3609
+ // Match string literals that look like project-relative storage paths:
3610
+ // "data/users.json", './db/posts.json', "uploads/", "logs/app.log"
3611
+ // Skip absolute paths, URLs, node_modules/, dotfiles.
3612
+ const re = /['"`](?:\.\/)?((?:data|db|storage|uploads|logs|tmp|cache|sessions)\/[A-Za-z0-9_\-./]+)['"`]/g;
3613
+ const stack = [projectDir];
3614
+ const seen = new Set();
3615
+ while (stack.length) {
3616
+ const cur = stack.pop();
3617
+ let entries;
3618
+ try { entries = fs.readdirSync(cur, { withFileTypes: true }); } catch { continue; }
3619
+ for (const ent of entries) {
3620
+ if (skipDirs.has(ent.name) || ent.name.startsWith('.')) continue;
3621
+ const abs = path.join(cur, ent.name);
3622
+ if (ent.isDirectory()) { stack.push(abs); continue; }
3623
+ if (!exts.has(path.extname(ent.name))) continue;
3624
+ let content;
3625
+ try { content = fs.readFileSync(abs, 'utf-8'); } catch { continue; }
3626
+ let m;
3627
+ re.lastIndex = 0;
3628
+ while ((m = re.exec(content)) !== null) {
3629
+ const rel = m[1].replace(/\\/g, '/');
3630
+ if (seen.has(rel)) continue;
3631
+ seen.add(rel);
3632
+ const fullPath = path.join(projectDir, rel);
3633
+ try {
3634
+ ensureDir(path.dirname(fullPath));
3635
+ // Only create file if it looks like a file (has extension) and doesn't exist
3636
+ if (path.extname(rel) && !fs.existsSync(fullPath)) {
3637
+ const ext = path.extname(rel).toLowerCase();
3638
+ let stub = '';
3639
+ if (ext === '.json') stub = rel.includes('users') || rel.includes('posts') || rel.includes('items') || rel.includes('list') ? '[]' : '{}';
3640
+ else if (ext === '.txt' || ext === '.log') stub = '';
3641
+ else if (ext === '.sqlite' || ext === '.db') continue; // skip binary
3642
+ else stub = '';
3643
+ fs.writeFileSync(fullPath, stub, 'utf-8');
3644
+ created.push(rel);
3645
+ }
3646
+ } catch {}
3647
+ }
3648
+ }
3649
+ }
3650
+ return created;
3651
+ }
3652
+
3653
+ export function autoRepairProject(projectName) {
3654
+ const dir = ProjectStore.dir(projectName);
3655
+ if (!fs.existsSync(dir)) throw new Error('project not found');
3656
+
3657
+ const repairs = [];
3658
+ const filesRepaired = new Set();
3659
+ const filesCreated = [];
3660
+
3661
+ // Phase 0: create missing data files referenced by code (data/X.json, etc)
3662
+ const dataCreated = _detectMissingDataFiles(dir);
3663
+ for (const f of dataCreated) {
3664
+ filesCreated.push(f);
3665
+ repairs.push({ file: f, kind: 'missing-data-file', source: 'code-reference' });
3666
+ }
3667
+
3668
+ // Walk every HTML file in the project
3669
+ const stack = [dir];
3670
+ const skipDirs = new Set(['node_modules', '.git', '.nha-shims', 'dist', 'build', '.next']);
3671
+ while (stack.length) {
3672
+ const cur = stack.pop();
3673
+ let entries;
3674
+ try { entries = fs.readdirSync(cur, { withFileTypes: true }); } catch { continue; }
3675
+ for (const ent of entries) {
3676
+ if (skipDirs.has(ent.name) || ent.name.startsWith('.')) continue;
3677
+ const abs = path.join(cur, ent.name);
3678
+ if (ent.isDirectory()) { stack.push(abs); continue; }
3679
+ const ext = path.extname(ent.name).toLowerCase();
3680
+ if (ext !== '.html' && ext !== '.htm') continue;
3681
+
3682
+ const rel = path.relative(dir, abs).replace(/\\/g, '/');
3683
+ let html;
3684
+ try { html = fs.readFileSync(abs, 'utf-8'); } catch { continue; }
3685
+
3686
+ // Phase A: balance tags
3687
+ const { fixed, edits } = _balanceHtmlTags(html);
3688
+ if (fixed !== html && edits.length > 0) {
3689
+ fs.writeFileSync(abs, fixed, 'utf-8');
3690
+ filesRepaired.add(rel);
3691
+ repairs.push({ file: rel, kind: 'html-balance', edits });
3692
+ }
3693
+
3694
+ // Phase B: create missing referenced assets
3695
+ const refs = _extractHtmlAssetRefs(fixed);
3696
+ for (const ref of refs) {
3697
+ const target = _normalizeAssetPath(ref.href, rel);
3698
+ if (!target) continue;
3699
+ const targetAbs = path.join(dir, target);
3700
+ if (fs.existsSync(targetAbs)) continue;
3701
+ // Don't create node_modules / external dirs
3702
+ if (target.startsWith('node_modules/') || target.includes('..')) continue;
3703
+ try {
3704
+ ensureDir(path.dirname(targetAbs));
3705
+ fs.writeFileSync(targetAbs, _placeholderContent(ref.kind, ref.href), 'utf-8');
3706
+ filesCreated.push(target);
3707
+ repairs.push({ file: target, kind: 'missing-asset', source: rel, ref: ref.href });
3708
+ } catch {}
3709
+ }
3710
+ }
3711
+ }
3712
+
3713
+ return {
3714
+ ok: true,
3715
+ filesRepaired: [...filesRepaired],
3716
+ filesCreated,
3717
+ repairs,
3718
+ summary: `${filesRepaired.size} HTML balanced, ${filesCreated.length} placeholder files created`,
3719
+ };
3720
+ }
3721
+
3722
+ // ─────────────────────────────────────────────────────────────────────────────
3723
+
3414
3724
  // Map native tool names → internal NHA "op" codes. Both directions: the LLM
3415
3725
  // might emit either based on which provider's docs it was trained on.
3416
3726
  const _TOOL_NAME_TO_OP = new Map([
@@ -3824,6 +4134,14 @@ const _LLM_ERROR_MARKERS = [
3824
4134
  /^\s*error code:\s*\d{3,4}/i,
3825
4135
  // Standalone HTTP status phrase at the start of a code file is suspicious
3826
4136
  /^\s*(HTTP\/[\d.]+\s+)?[45]\d{2}\s+/,
4137
+ // NHA/Liara backend retry-wrapper errors leaked as file content:
4138
+ // "/* Retry: NHA Free 502: {"error":"Failed to reach Liara",...}"
4139
+ // "Retry: NHA 503", "// NHA Free Error 429"
4140
+ /^\s*(?:\/\*\s*|\/\/\s*)?Retry:?\s*NHA(\s+Free)?(\s+\d{3})?/i,
4141
+ /^\s*(?:\/\*\s*|\/\/\s*)?Failed to reach (Liara|NHA|OpenAI|Anthropic|Gemini|provider)/i,
4142
+ /^\s*\{?\s*"error"\s*:\s*"Failed to reach/i,
4143
+ // Plain "fetch failed", "ECONNRESET" etc. as first line of a code file
4144
+ /^\s*(?:\/\*\s*|\/\/\s*)?(?:fetch failed|ECONNRESET|ECONNREFUSED|ETIMEDOUT)\b/i,
3827
4145
  ];
3828
4146
 
3829
4147
  function _looksLikeLLMError(content) {
@@ -852,8 +852,8 @@ Errore: `+e.msg,L(!1))}catch{}}}}catch(e){e instanceof DOMException&&e.name===`A
852
852
 
853
853
  `);i=a.pop()??``;for(let e of a){let t=e.replace(/^data: /,``).trim();if(t)try{let e=JSON.parse(t);(e.type===`phase`||e.type===`status`||e.type===`log`||e.type===`warn`||e.type===`error`)&&_t(t=>[...t.slice(-49),{kind:e.type,msg:String(e.msg||``),ts:Date.now()}]),e.type===`ready`&&e.port?(lt(e.port),pt(!1)):e.type===`error`&&ht(e.msg)}catch{}}}}catch(e){ht(e.message||`Connection failed`)}pt(!1)}}async function Gt(){c&&await Wt(c)}(0,_.useEffect)(()=>{z.current=V,Ot.current=Gt});async function Kt(){if(!et||!c)return;let e=await E(`/api/studio/webcraft/grep`,{projectName:c,query:et});e?.matches&&rt(e.matches)}function qt(e){let t=g.findIndex(t=>t.name===e);t>=0&&(b(t),i(`files`))}function Jt(){window.open(`/api/studio/webcraft/download/${encodeURIComponent(c)}`,`_blank`)}async function Yt(e,t,n,r){t.endsWith(`.md`)||(t+=`.md`);let i={name:t,content:n,type:r},a;a=e.mode===`edit`&&e.idx!==null?We.map((t,n)=>n===e.idx?i:t):[...We,i],Ge(a),Ye(null);let o=c||`MyProject`;c||l(o),await E(`/api/studio/webcraft/skills/${encodeURIComponent(o)}`,{skills:a})}async function Xt(e){let t=We[e];!t||!confirm(`Eliminare "${t.name}"?`)||(await E(`/api/studio/webcraft/skills/${encodeURIComponent(c)}/delete`,{name:t.name}),Ge(We.filter((t,n)=>n!==e)))}async function Zt(e){let t=We[e];if(!t||!confirm(`Svuotare "${t.name}"? Il file rimane ma il contenuto viene cancellato.`))return;let n=We.map((t,n)=>n===e?{...t,content:``}:t);Ge(n),await E(`/api/studio/webcraft/skills/${encodeURIComponent(c)}`,{skills:n})}async function Qt(){let e=await T(`/api/studio/webcraft/projects`);e?.projects&&st(e.projects)}async function H(e){let t=await T(`/api/studio/webcraft/projects/load/${encodeURIComponent(e.name)}`);if(!t)return;let r=t.projectName??e.name;l(r),d(t.description??``),v(t.files??[]),b(0),n(`new`),i(`files`),Ie([]),Ge([]),qe(!1),pe([]),kt(r);let a=await T(`/api/studio/webcraft/projects/chat/load/${encodeURIComponent(r)}`);a?.chat&&Ie(a.chat);let o=await T(`/api/studio/webcraft/skills/${encodeURIComponent(r)}`);o?.skills&&(Ge(o.skills),qe(!0))}async function $t(e){confirm(`Eliminare: ${e.name} - ${e.dir}?`)&&(await E(`/api/studio/webcraft/projects/${encodeURIComponent(e.name)}`,{},`DELETE`),st(ot.filter(t=>t.name!==e.name)),c===e.name&&(l(``),v([]),Ie([]),d(``)))}async function en(){if(!He)return;let e=He.originalMessage;Ue(null),await Ft(e+`
854
854
  [Piano approvato — procedi con le modifiche]`,null,[])}function tn(e){e&&Array.from(e).forEach(e=>{let t=new FileReader;t.onload=t=>{let n=(t.target?.result).split(`,`)[1];Ve(t=>[...t,{name:e.name,mimeType:e.type,base64:n,size:e.size}])},t.readAsDataURL(e)})}let nn=c&&g.length>0,rn=g[y],U=ze||N;return(0,k.jsxs)(`div`,{className:Q.root,children:[(0,k.jsxs)(`div`,{className:Q.header,children:[(0,k.jsxs)(`div`,{children:[(0,k.jsxs)(`div`,{className:Q.title,children:[`⚙ WebCraft`,c?` — ${c}`:``]}),!c&&(0,k.jsx)(`div`,{className:Q.subtitle,children:`Genera progetti web completi con agenti AI`})]}),(0,k.jsxs)(`div`,{className:Q.headerTabs,children:[(0,k.jsx)(`button`,{className:`${Q.tabBtn} ${t===`new`?Q.tabActive:``}`,onClick:async()=>{if(!(ee.size>0&&!confirm(`${ee.size} unsaved file(s). Discard changes and create new project?`))){if(ct){try{await fetch(`/api/studio/webcraft/sandbox`,{method:`DELETE`})}catch{}lt(null)}v([]),b(0),S(null),w(null),te(new Set),Ie([]),l(``),d(``),Re(``),Ge([]),qe(!1),Pe(null),Ce(!1),L(!1),oe(!1),ce(null),n(`new`)}},children:`+ Nuovo`}),(0,k.jsx)(`button`,{className:`${Q.tabBtn} ${t===`projects`?Q.tabActive:``}`,onClick:()=>{n(`projects`),Qt()},children:`📁 Progetti`})]})]}),(0,k.jsx)(`div`,{className:Q.body,children:t===`projects`?(0,k.jsx)(`div`,{className:Q.projectsList,children:ot.length===0?(0,k.jsxs)(`div`,{className:Q.emptyProjects,children:[(0,k.jsx)(`span`,{className:Q.emptyIcon,children:`📁`}),(0,k.jsx)(`span`,{children:e(`webcraft.noProjects`)}),(0,k.jsx)(`span`,{className:Q.emptyHint,children:`Crea un progetto nella tab Nuovo`})]}):ot.map(e=>(0,k.jsxs)(`div`,{className:Q.projectCard,children:[(0,k.jsxs)(`div`,{className:Q.projectInfo,children:[(0,k.jsx)(`div`,{className:Q.projectName,children:e.name}),(0,k.jsx)(`div`,{className:Q.projectDesc,children:e.description}),(0,k.jsxs)(`div`,{className:Q.projectMeta,children:[(0,k.jsxs)(`span`,{children:[`📄 `,e.fileCount,` file`]}),(0,k.jsxs)(`span`,{children:[`📅 `,e.createdAt?new Date(e.createdAt).toLocaleString():``]})]})]}),(0,k.jsx)(`button`,{className:Q.openBtn,onClick:()=>H(e),children:`↗ Apri`}),(0,k.jsx)(`button`,{className:Q.deleteBtn,onClick:()=>$t(e),children:`🗑`})]},e.name))}):(0,k.jsxs)(`div`,{className:Q.editor,"data-mobile-view":a?o:void 0,children:[(0,k.jsxs)(`div`,{className:Q.examples,children:[(0,k.jsx)(`div`,{className:Q.sectionLabel,children:`Esempi`}),(0,k.jsx)(`div`,{className:Q.examplePills,children:eE.map(e=>(0,k.jsx)(`button`,{className:Q.examplePill,onClick:()=>{l(e.name),d(e.desc),Re(e.desc)},children:e.name},e.name))})]}),(0,k.jsxs)(`div`,{className:Q.editorCols,children:[(0,k.jsxs)(`div`,{className:Q.leftSidebar,children:[(0,k.jsxs)(`div`,{className:Q.panel,children:[(0,k.jsx)(`div`,{className:Q.panelTitle,children:`Blocchi`}),tE.map(e=>(0,k.jsxs)(`label`,{className:Q.blockLabel,children:[(0,k.jsx)(`input`,{type:`checkbox`,checked:f[e.key],onChange:t=>p(n=>({...n,[e.key]:t.target.checked})),className:Q.blockCheck}),(0,k.jsx)(`span`,{children:e.icon}),(0,k.jsx)(`span`,{children:e.label})]},e.key))]}),f.auth&&(0,k.jsxs)(`div`,{className:Q.panel,children:[(0,k.jsxs)(`div`,{className:Q.panelHeader,children:[(0,k.jsx)(`div`,{className:Q.panelTitle,children:`Campi Auth`}),(0,k.jsx)(`button`,{className:Q.addBtn,onClick:()=>h(e=>[...e,{label:`New field`,type:`text`,required:!1}]),children:`+ Campo`})]}),m.map((e,t)=>(0,k.jsxs)(`div`,{className:Q.authField,children:[(0,k.jsx)(`input`,{value:e.label,onChange:e=>h(n=>n.map((n,r)=>r===t?{...n,label:e.target.value}:n)),className:Q.authFieldInput}),(0,k.jsx)(`select`,{value:e.type,onChange:e=>h(n=>n.map((n,r)=>r===t?{...n,type:e.target.value}:n)),className:Q.authFieldSelect,children:[`text`,`email`,`password`,`tel`,`date`,`number`].map(e=>(0,k.jsx)(`option`,{value:e,children:e},e))}),(0,k.jsx)(`input`,{type:`checkbox`,checked:e.required,onChange:e=>h(n=>n.map((n,r)=>r===t?{...n,required:e.target.checked}:n)),title:`Required`,className:Q.authFieldReq}),(0,k.jsx)(`button`,{onClick:()=>h(e=>e.filter((e,n)=>n!==t)),className:Q.removeFieldBtn,children:`×`})]},t))]}),(0,k.jsxs)(`div`,{className:Q.panel,children:[(0,k.jsxs)(`div`,{className:Q.panelHeader,children:[(0,k.jsx)(`div`,{className:Q.panelTitle,children:`🗂 Contesto AI`}),(0,k.jsx)(`button`,{className:Q.addBtn,onClick:()=>Ye({mode:`new`,idx:null,name:``,content:``,type:`skill`,generating:!1}),children:`+ Skill`})]}),We.length>0?(0,k.jsx)(`div`,{className:Q.skillsList,children:We.map((e,t)=>(0,k.jsxs)(`div`,{className:Q.skillRow,children:[(0,k.jsx)(`span`,{className:Q.skillIcon,children:aE(e.type)}),(0,k.jsx)(`span`,{className:Q.skillName,title:e.name,children:e.name}),(0,k.jsx)(`span`,{className:`${Q.skillBadge} ${Q[`skillBadge_`+e.type]}`,children:e.type}),!e.content&&e.type!==`log`&&(0,k.jsx)(`span`,{className:Q.skillEmpty,children:`⚠`}),(0,k.jsx)(`button`,{className:Q.skillBtn,onClick:()=>Ye({mode:e.type===`log`?`view`:`edit`,idx:t,name:e.name,content:e.content,type:e.type,generating:!1}),children:e.type===`log`?`👁`:`✏`}),e.type!==`memory`&&e.type!==`provider`&&e.type!==`log`&&(0,k.jsx)(`button`,{className:Q.skillBtn,onClick:()=>Zt(t),children:`🗑`}),e.type===`log`&&(0,k.jsx)(`button`,{className:Q.skillBtn,onClick:()=>Xt(t),children:`🗑`})]},t))}):(0,k.jsx)(`div`,{className:Q.skillsEmpty,children:Ke?`Nessun file di contesto. Clicca "+ Skill" per aggiungerne uno.`:`Crea o carica un progetto per i file di contesto.`})]}),Xe.length>0&&(0,k.jsxs)(`div`,{className:Q.panel,children:[(0,k.jsx)(`div`,{className:Q.panelTitle,children:`💾 Snapshot`}),Xe.slice(0,5).map(e=>{let t=e.ts.replace(`T`,` `).slice(0,16);return(0,k.jsxs)(`div`,{className:Q.snapshotRow,children:[(0,k.jsx)(`span`,{className:Q.snapshotTs,children:t}),(0,k.jsxs)(`span`,{className:Q.snapshotCount,children:[e.fileCount,`f`]}),(0,k.jsx)(`button`,{className:Q.snapshotBtn,onClick:()=>Vt(e.ts),children:`↺`})]},e.ts)})]}),N&&(0,k.jsx)(`div`,{className:Q.genStatus,children:`⏳ Generazione...`}),we&&(0,k.jsxs)(`div`,{className:Q.repairStatus,children:[(0,k.jsx)(`div`,{className:Q.repairStatusTitle,children:`🔧 Correzione automatica...`}),(0,k.jsxs)(`div`,{className:Q.repairStatusProg,children:[Ee,` / `,De,` file`]}),(0,k.jsx)(`div`,{className:Q.repairStatusFile,children:ke})]}),g.length>0&&!N&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:Q.actionRow,children:[(0,k.jsx)(`button`,{className:Q.actionBtn,onClick:Jt,children:`⬇ ZIP`}),(0,k.jsx)(`button`,{className:Q.actionBtnIcon,title:`Syntax check`,onClick:Ht,children:`✅`}),(0,k.jsx)(`button`,{className:`${Q.actionBtnIcon} ${Qe?Q.actionBtnActive:``}`,title:`Grep`,onClick:()=>$e(!Qe),children:`🔍`}),(0,k.jsx)(`button`,{className:Q.actionBtnIcon,title:`Snapshot`,onClick:zt,children:`💾`})]}),g.some(e=>e._error||e._syntaxError)&&!we&&(0,k.jsx)(`button`,{className:Q.repairBtn,onClick:V,children:`🔧 Correggi tutti i file rossi`}),(0,k.jsx)(`button`,{className:Q.sandboxBtn,onClick:()=>{c?Wt(c):i(`preview`)},children:ft?`⏳ Starting...`:ct?`🌐 Sandbox Live`:`▶ Sandbox`}),Ne&&(0,k.jsxs)(`div`,{className:Q.statsBar,children:[(0,k.jsxs)(`span`,{children:[`⏱ `,Ne.seconds>=60?`${Math.floor(Ne.seconds/60)}m ${Ne.seconds%60}s`:`${Ne.seconds}s`]}),(0,k.jsxs)(`span`,{children:[`↑ `,Ne.tokIn.toLocaleString(),` tok`]}),(0,k.jsxs)(`span`,{children:[`↓ `,Ne.tokOut.toLocaleString(),` tok`]}),(0,k.jsxs)(`span`,{children:[`📄 `,Ne.files,` file`]})]})]})]}),(0,k.jsxs)(`div`,{className:Q.rightPanel,children:[(0,k.jsxs)(`div`,{className:Q.rightTabBar,children:[(0,k.jsx)(`button`,{className:`${Q.rightTab} ${r===`preview`?``:Q.rightTabActive}`,onClick:()=>i(`files`),children:`📄 File`}),(0,k.jsx)(`button`,{className:`${Q.rightTab} ${r===`preview`?Q.rightTabActive:``}`,onClick:()=>i(`preview`),children:`🌐 Sandbox`})]}),we&&(0,k.jsxs)(`div`,{className:Q.repairBar,children:[(0,k.jsxs)(`div`,{className:Q.repairBarRow,children:[(0,k.jsx)(`span`,{className:Q.repairBarIcon,children:`🔧`}),(0,k.jsx)(`span`,{className:Q.repairBarLabel,children:`Auto-fix`}),(0,k.jsx)(`span`,{className:Q.repairBarFile,children:ke}),(0,k.jsxs)(`span`,{className:Q.repairBarCounter,children:[Ee,` / `,De]}),(0,k.jsx)(`span`,{className:Q.repairBarTime,children:R}),(0,k.jsx)(`button`,{className:Q.stopBtn,onClick:Lt,children:`⏹ Stop`})]}),(0,k.jsx)(`div`,{className:Q.progressTrack,children:(0,k.jsx)(`div`,{className:Q.repairProgress,style:{width:De>0?`${Math.round(Ee/De*100)}%`:`0%`}})})]}),N&&(0,k.jsxs)(`div`,{className:Q.genBar,children:[(0,k.jsxs)(`div`,{className:Q.genBarRow,children:[(0,k.jsx)(`span`,{className:Q.genBarRobot,children:`🤖`}),(0,k.jsx)(`span`,{className:Q.genBarLabel,children:I.total===0?`Pianificazione...`:`Generazione`}),(0,k.jsx)(`span`,{className:Q.genBarFile,children:(I.name||``).split(`,`)[0].trim()}),(0,k.jsx)(`span`,{className:Q.genBarCounter,children:I.total>0?`${I.fi} / ${I.total}`:``}),(0,k.jsx)(`span`,{className:Q.genBarCounter,children:je.tokIn+je.tokOut>0?`↑${jt(je.tokIn)} ↓${jt(je.tokOut)}`:``}),(0,k.jsx)(`span`,{className:Q.genBarTime,children:vt}),(0,k.jsxs)(`span`,{className:Q.genDots,children:[(0,k.jsx)(`span`,{className:`${Q.dot} ${Q.dot1}`}),(0,k.jsx)(`span`,{className:`${Q.dot} ${Q.dot2}`}),(0,k.jsx)(`span`,{className:`${Q.dot} ${Q.dot3}`})]})]}),(0,k.jsx)(`div`,{className:Q.progressTrack,children:(0,k.jsx)(`div`,{className:Q.genProgress,style:{width:I.total>0?`${Math.round(I.fi/I.total*100)}%`:`0%`}})})]}),r===`preview`?(0,k.jsxs)(`div`,{className:Q.sandboxWrap,children:[(0,k.jsxs)(`div`,{className:Q.sandboxStatusBar,children:[(0,k.jsx)(`span`,{className:Q.sandboxStatusDot,style:{background:ct?`#4ade80`:ft?`#facc15`:`#64748b`}}),(0,k.jsx)(`span`,{className:Q.sandboxStatusText,children:ct?`Live :${ct}`:ft?`Starting...`:`Stopped`}),ct&&(0,k.jsx)(`button`,{className:Q.sandboxReloadBtn,onClick:()=>{let e=document.querySelector(`iframe[title="WebCraft Sandbox"]`);e&&(e.src=e.src)},children:`↻`}),ct&&(0,k.jsx)(`button`,{className:Q.sandboxStopBtn,onClick:async()=>{lt(null),M([]);try{await fetch(`/api/studio/webcraft/sandbox`,{method:`DELETE`})}catch{}},children:`⏹`}),!ct&&!ft&&(0,k.jsx)(`button`,{className:Q.sandboxStartBtnSmall,onClick:()=>{c&&Wt(c)},children:`▶ Start`})]}),de.length>0&&(0,k.jsxs)(`div`,{className:Q.runtimeErrors,children:[(0,k.jsxs)(`div`,{className:Q.runtimeErrorsHeader,children:[(0,k.jsxs)(`span`,{children:[`❌ `,de.length,` runtime error`,de.length>1?`s`:``]}),(0,k.jsx)(`button`,{className:Q.runtimeErrorsFix,onClick:()=>{let e=`Fix these runtime errors. Use edit_file (or create_file if the file doesn't exist) to actually modify the source — do NOT respond with text descriptions. After each fix, call check_syntax to verify. If edit_file fails because old_text doesn't match, read_file again and retry with the exact text.\n\n${de.map(e=>`${e.message} (${e.source||``}:${e.line||0})`).join(`
855
- `)}`;fetch(`/api/studio/webcraft/sandbox/errors`,{method:`DELETE`}),M([]),i(`files`),Pt(e)},children:`🔧 Auto-fix`}),(0,k.jsx)(`button`,{className:Q.runtimeErrorsDismiss,onClick:()=>{fetch(`/api/studio/webcraft/sandbox/errors`,{method:`DELETE`}),M([])},children:`✕`})]}),de.slice(0,3).map((e,t)=>(0,k.jsxs)(`div`,{className:Q.runtimeErrorLine,children:[e.message,e.source?` — ${e.source.split(`/`).pop()}:${e.line}`:``]},t))]}),ct?(0,k.jsx)(`iframe`,{src:`http://localhost:${ct}`,className:Q.sandboxFrame,title:`WebCraft Sandbox`,sandbox:`allow-scripts allow-same-origin allow-forms allow-popups`}):(0,k.jsxs)(`div`,{className:Q.sandboxEmpty,children:[(0,k.jsx)(`span`,{style:{fontSize:48},children:ft?`⏳`:mt?`❌`:`🌐`}),(0,k.jsx)(`span`,{style:{fontWeight:700,fontSize:16},children:ft?`Starting sandbox...`:mt?`Sandbox Error`:`Preview`}),mt&&(0,k.jsx)(`pre`,{style:{fontSize:11,maxWidth:600,textAlign:`left`,color:`#f87171`,background:`rgba(248,113,113,0.08)`,border:`1px solid rgba(248,113,113,0.2)`,borderRadius:6,padding:`8px 12px`,whiteSpace:`pre-wrap`,wordBreak:`break-word`,margin:`8px 0`,lineHeight:1.5,maxHeight:200,overflow:`auto`},children:mt}),gt.length>0&&(0,k.jsxs)(`div`,{style:{width:`100%`,maxWidth:720,margin:`8px 0`,textAlign:`left`},children:[(0,k.jsxs)(`div`,{style:{fontSize:10,color:`#94a3b8`,textTransform:`uppercase`,letterSpacing:`0.5px`,marginBottom:4},children:[`Sandbox log (`,gt.length,`)`]}),(0,k.jsx)(`pre`,{style:{fontSize:11,lineHeight:1.5,fontFamily:`SF Mono, Monaco, monospace`,background:`rgba(15, 23, 42, 0.6)`,border:`1px solid rgba(148, 163, 184, 0.18)`,borderRadius:6,padding:`8px 12px`,maxHeight:240,overflow:`auto`,whiteSpace:`pre-wrap`,wordBreak:`break-word`,color:`#cbd5e1`},children:gt.slice(-40).map((e,t)=>(0,k.jsx)(`div`,{style:{color:e.kind===`error`?`#f87171`:e.kind===`warn`?`#fbbf24`:e.kind===`phase`?`#60a5fa`:e.kind===`status`?`#34d399`:`#94a3b8`},children:`[${e.kind}] ${e.msg}`},t))})]}),!ft&&(0,k.jsxs)(`button`,{className:Q.sandboxStartBtn,onClick:()=>{c&&Wt(c)},children:[`▶ `,mt?`Retry`:`Start Sandbox`]})]})]}):(0,k.jsx)(`div`,{className:Q.codeArea,children:g.length===0&&N?(0,k.jsx)(`div`,{className:Q.noFiles,children:(0,k.jsxs)(`div`,{className:Q.noFilesHero,children:[(0,k.jsx)(`span`,{className:Q.noFilesIcon,children:`⏳`}),(0,k.jsx)(`span`,{className:Q.noFilesTitle,children:`Pianificazione...`}),(0,k.jsx)(`span`,{className:Q.noFilesTagline,children:I.name||`Analisi della struttura del progetto in corso`})]})}):g.length===0?(0,k.jsxs)(`div`,{className:Q.noFiles,children:[(0,k.jsxs)(`div`,{className:Q.noFilesHero,children:[(0,k.jsx)(`span`,{className:Q.noFilesIcon,children:`🔨`}),(0,k.jsx)(`span`,{className:Q.noFilesTitle,children:`WebCraft`}),(0,k.jsx)(`span`,{className:Q.noFilesTagline,children:`Genera progetti web completi con AI`})]}),(0,k.jsxs)(`div`,{className:Q.noFilesSteps,children:[(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`1`}),(0,k.jsx)(`span`,{children:`Scegli un esempio o scrivi una descrizione nel box in basso`})]}),(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`2`}),(0,k.jsxs)(`span`,{children:[`Premi `,(0,k.jsx)(`strong`,{children:`▶ Genera`}),` — l'AI crea tutti i file del progetto`]})]}),(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`3`}),(0,k.jsx)(`span`,{children:`Chiedi modifiche in chat, scarica lo ZIP o avvia il Sandbox`})]})]}),(0,k.jsxs)(`div`,{className:Q.noFilesExamplesHint,children:[`💡 Prova: `,(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[0];l(e.name),d(e.desc),Re(e.desc)},children:`MySaaS`}),(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[1];l(e.name),d(e.desc),Re(e.desc)},children:`MyShop`}),(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[3];l(e.name),d(e.desc),Re(e.desc)},children:`MyPortfolio`})]})]}):(0,k.jsxs)(`div`,{className:Q.codeLayout,children:[(0,k.jsx)(`div`,{className:Q.ideTabBar,children:g.map((e,t)=>{let n=e._error||!!e._syntaxError,r=t===y;return(0,k.jsxs)(`button`,{className:`${Q.ideTab} ${r?Q.ideTabActive:``} ${n?Q.ideTabError:``} ${e._pending?Q.ideTabPending:``}`,onClick:()=>{b(t),w(null),S(null),N&&me.current!==null&&t!==me.current&&(he.current&&clearTimeout(he.current),he.current=setTimeout(()=>{me.current!==null&&(b(me.current),S(null))},1e4))},title:e.name,children:[(0,k.jsx)(`span`,{className:Q.ideTabIcon,children:e._pending?`⌛`:n?`⚠`:rE(e.name)}),(0,k.jsx)(`span`,{className:Q.ideTabName,children:(e.name||``).split(`/`).pop()}),ee.has(e.name)&&(0,k.jsx)(`span`,{className:Q.ideTabUnsaved,children:`●`}),n&&(0,k.jsx)(`span`,{className:Q.ideTabDot})]},t)})}),xe&&(0,k.jsxs)(`div`,{className:Q.diffOverlay,children:[(0,k.jsxs)(`div`,{className:Q.diffOverlayHeader,children:[(0,k.jsxs)(`span`,{children:[`✏ Modifica proposta — `,(0,k.jsx)(`strong`,{children:xe.file})]}),(0,k.jsxs)(`div`,{className:Q.diffOverlayActions,children:[(0,k.jsx)(`button`,{className:Q.diffAcceptBtn,onClick:()=>{v(e=>e.map(e=>e.name===xe.file?{...e,content:xe.after}:e)),Se(null)},children:`✓ Accetta`}),(0,k.jsx)(`button`,{className:Q.diffRejectBtn,onClick:()=>Se(null),children:`✕ Rifiuta`})]})]}),(0,k.jsx)(`div`,{className:Q.diffOverlayBody,children:(0,k.jsx)(uE,{before:xe.before,after:xe.after})})]}),(0,k.jsxs)(`div`,{className:Q.codeRow,children:[(0,k.jsxs)(`div`,{className:Q.fileTreeWrap,children:[fe.length>0&&(0,k.jsxs)(`div`,{className:Q.scanBanner,children:[(0,k.jsx)(`span`,{className:Q.scanBannerIcon,children:`⚠`}),(0,k.jsxs)(`span`,{className:Q.scanBannerText,children:[fe.length,` issue`,fe.length>1?`s`:``]}),(0,k.jsx)(`button`,{className:Q.scanBannerFix,onClick:()=>{let e=`Fix ALL these issues by editing the source files. Workflow per issue: read_file → edit_file (or create_file if missing) → check_syntax. Do NOT respond with a plan or description — call the tools and actually modify the code. If edit_file returns an error because old_text doesn't match, read_file again and retry with the exact text. Also check that any /js/*.js, /css/*.css referenced in HTML actually exist as files (create them if missing).\n\nISSUES TO FIX:\n${fe.map(e=>`[${e.severity}] ${e.file}: ${e.message}`).join(`
856
- `)}`;i(`files`),Pt(e)},children:`Fix`})]}),(0,k.jsx)(WT,{files:g,activeIndex:y,unsavedFiles:ee,errorFiles:new Set(fe.filter(e=>e.severity===`error`).map(e=>e.file)),onSelect:e=>{b(e),w(null),S(null),N&&me.current!==null&&e!==me.current&&(he.current&&clearTimeout(he.current),he.current=setTimeout(()=>{me.current!==null&&(b(me.current),S(null))},1e4))}})]}),(0,k.jsx)(`div`,{className:Q.codeEditorWrap,children:rn&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:Q.codeHeader,children:[(0,k.jsx)(`span`,{className:Q.codeFileIcon,children:rE(rn.name)}),(0,k.jsx)(`span`,{className:Q.codeFileName,children:rn.name}),rn.content&&!rn._error&&(0,k.jsxs)(`span`,{className:Q.codeFileMeta,children:[(rn.content||``).split(`
855
+ `)}`;fetch(`/api/studio/webcraft/sandbox/errors`,{method:`DELETE`}),M([]),i(`files`),Pt(e)},children:`🔧 Auto-fix`}),(0,k.jsx)(`button`,{className:Q.runtimeErrorsDismiss,onClick:()=>{fetch(`/api/studio/webcraft/sandbox/errors`,{method:`DELETE`}),M([])},children:`✕`})]}),de.slice(0,3).map((e,t)=>(0,k.jsxs)(`div`,{className:Q.runtimeErrorLine,children:[e.message,e.source?` — ${e.source.split(`/`).pop()}:${e.line}`:``]},t))]}),ct?(0,k.jsx)(`iframe`,{src:`http://localhost:${ct}`,className:Q.sandboxFrame,title:`WebCraft Sandbox`,sandbox:`allow-scripts allow-same-origin allow-forms allow-popups`}):(0,k.jsxs)(`div`,{className:Q.sandboxEmpty,children:[(0,k.jsx)(`span`,{style:{fontSize:48},children:ft?`⏳`:mt?`❌`:`🌐`}),(0,k.jsx)(`span`,{style:{fontWeight:700,fontSize:16},children:ft?`Starting sandbox...`:mt?`Sandbox Error`:`Preview`}),mt&&(0,k.jsx)(`pre`,{style:{fontSize:11,maxWidth:600,textAlign:`left`,color:`#f87171`,background:`rgba(248,113,113,0.08)`,border:`1px solid rgba(248,113,113,0.2)`,borderRadius:6,padding:`8px 12px`,whiteSpace:`pre-wrap`,wordBreak:`break-word`,margin:`8px 0`,lineHeight:1.5,maxHeight:200,overflow:`auto`},children:mt}),gt.length>0&&(0,k.jsxs)(`div`,{style:{width:`100%`,maxWidth:720,margin:`8px 0`,textAlign:`left`},children:[(0,k.jsxs)(`div`,{style:{fontSize:10,color:`#94a3b8`,textTransform:`uppercase`,letterSpacing:`0.5px`,marginBottom:4},children:[`Sandbox log (`,gt.length,`)`]}),(0,k.jsx)(`pre`,{style:{fontSize:11,lineHeight:1.5,fontFamily:`SF Mono, Monaco, monospace`,background:`rgba(15, 23, 42, 0.6)`,border:`1px solid rgba(148, 163, 184, 0.18)`,borderRadius:6,padding:`8px 12px`,maxHeight:240,overflow:`auto`,whiteSpace:`pre-wrap`,wordBreak:`break-word`,color:`#cbd5e1`},children:gt.slice(-40).map((e,t)=>(0,k.jsx)(`div`,{style:{color:e.kind===`error`?`#f87171`:e.kind===`warn`?`#fbbf24`:e.kind===`phase`?`#60a5fa`:e.kind===`status`?`#34d399`:`#94a3b8`},children:`[${e.kind}] ${e.msg}`},t))})]}),!ft&&(0,k.jsxs)(`button`,{className:Q.sandboxStartBtn,onClick:()=>{c&&Wt(c)},children:[`▶ `,mt?`Retry`:`Start Sandbox`]})]})]}):(0,k.jsx)(`div`,{className:Q.codeArea,children:g.length===0&&N?(0,k.jsx)(`div`,{className:Q.noFiles,children:(0,k.jsxs)(`div`,{className:Q.noFilesHero,children:[(0,k.jsx)(`span`,{className:Q.noFilesIcon,children:`⏳`}),(0,k.jsx)(`span`,{className:Q.noFilesTitle,children:`Pianificazione...`}),(0,k.jsx)(`span`,{className:Q.noFilesTagline,children:I.name||`Analisi della struttura del progetto in corso`})]})}):g.length===0?(0,k.jsxs)(`div`,{className:Q.noFiles,children:[(0,k.jsxs)(`div`,{className:Q.noFilesHero,children:[(0,k.jsx)(`span`,{className:Q.noFilesIcon,children:`🔨`}),(0,k.jsx)(`span`,{className:Q.noFilesTitle,children:`WebCraft`}),(0,k.jsx)(`span`,{className:Q.noFilesTagline,children:`Genera progetti web completi con AI`})]}),(0,k.jsxs)(`div`,{className:Q.noFilesSteps,children:[(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`1`}),(0,k.jsx)(`span`,{children:`Scegli un esempio o scrivi una descrizione nel box in basso`})]}),(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`2`}),(0,k.jsxs)(`span`,{children:[`Premi `,(0,k.jsx)(`strong`,{children:`▶ Genera`}),` — l'AI crea tutti i file del progetto`]})]}),(0,k.jsxs)(`div`,{className:Q.noFilesStep,children:[(0,k.jsx)(`span`,{className:Q.noFilesStepNum,children:`3`}),(0,k.jsx)(`span`,{children:`Chiedi modifiche in chat, scarica lo ZIP o avvia il Sandbox`})]})]}),(0,k.jsxs)(`div`,{className:Q.noFilesExamplesHint,children:[`💡 Prova: `,(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[0];l(e.name),d(e.desc),Re(e.desc)},children:`MySaaS`}),(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[1];l(e.name),d(e.desc),Re(e.desc)},children:`MyShop`}),(0,k.jsx)(`button`,{className:Q.noFilesExampleBtn,onClick:()=>{let e=eE[3];l(e.name),d(e.desc),Re(e.desc)},children:`MyPortfolio`})]})]}):(0,k.jsxs)(`div`,{className:Q.codeLayout,children:[(0,k.jsx)(`div`,{className:Q.ideTabBar,children:g.map((e,t)=>{let n=e._error||!!e._syntaxError,r=t===y;return(0,k.jsxs)(`button`,{className:`${Q.ideTab} ${r?Q.ideTabActive:``} ${n?Q.ideTabError:``} ${e._pending?Q.ideTabPending:``}`,onClick:()=>{b(t),w(null),S(null),N&&me.current!==null&&t!==me.current&&(he.current&&clearTimeout(he.current),he.current=setTimeout(()=>{me.current!==null&&(b(me.current),S(null))},1e4))},title:e.name,children:[(0,k.jsx)(`span`,{className:Q.ideTabIcon,children:e._pending?`⌛`:n?`⚠`:rE(e.name)}),(0,k.jsx)(`span`,{className:Q.ideTabName,children:(e.name||``).split(`/`).pop()}),ee.has(e.name)&&(0,k.jsx)(`span`,{className:Q.ideTabUnsaved,children:`●`}),n&&(0,k.jsx)(`span`,{className:Q.ideTabDot})]},t)})}),xe&&(0,k.jsxs)(`div`,{className:Q.diffOverlay,children:[(0,k.jsxs)(`div`,{className:Q.diffOverlayHeader,children:[(0,k.jsxs)(`span`,{children:[`✏ Modifica proposta — `,(0,k.jsx)(`strong`,{children:xe.file})]}),(0,k.jsxs)(`div`,{className:Q.diffOverlayActions,children:[(0,k.jsx)(`button`,{className:Q.diffAcceptBtn,onClick:()=>{v(e=>e.map(e=>e.name===xe.file?{...e,content:xe.after}:e)),Se(null)},children:`✓ Accetta`}),(0,k.jsx)(`button`,{className:Q.diffRejectBtn,onClick:()=>Se(null),children:`✕ Rifiuta`})]})]}),(0,k.jsx)(`div`,{className:Q.diffOverlayBody,children:(0,k.jsx)(uE,{before:xe.before,after:xe.after})})]}),(0,k.jsxs)(`div`,{className:Q.codeRow,children:[(0,k.jsxs)(`div`,{className:Q.fileTreeWrap,children:[fe.length>0&&(0,k.jsxs)(`div`,{className:Q.scanBanner,children:[(0,k.jsx)(`span`,{className:Q.scanBannerIcon,children:`⚠`}),(0,k.jsxs)(`span`,{className:Q.scanBannerText,children:[fe.length,` issue`,fe.length>1?`s`:``]}),(0,k.jsx)(`button`,{className:Q.scanBannerFix,onClick:async()=>{i(`files`);try{let e=await E(`/api/studio/webcraft/auto-repair`,{projectName:c});if(e?.summary){let t=(e.repairs||[]).slice(0,20).map(e=>`${e.file} (${e.kind}${e.source?` from ${e.source}`:``})`).join(`
856
+ `);Ie(n=>[...n,{role:`agent`,text:`🔧 Auto-repair: ${e.summary}\n${t}`,tools:[]}])}await It([...e?.filesRepaired||[],...e?.filesCreated||[]],{}),await kt(c)}catch(e){console.error(`[auto-repair] failed:`,e)}},children:`Fix`})]}),(0,k.jsx)(WT,{files:g,activeIndex:y,unsavedFiles:ee,errorFiles:new Set(fe.filter(e=>e.severity===`error`).map(e=>e.file)),onSelect:e=>{b(e),w(null),S(null),N&&me.current!==null&&e!==me.current&&(he.current&&clearTimeout(he.current),he.current=setTimeout(()=>{me.current!==null&&(b(me.current),S(null))},1e4))}})]}),(0,k.jsx)(`div`,{className:Q.codeEditorWrap,children:rn&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:Q.codeHeader,children:[(0,k.jsx)(`span`,{className:Q.codeFileIcon,children:rE(rn.name)}),(0,k.jsx)(`span`,{className:Q.codeFileName,children:rn.name}),rn.content&&!rn._error&&(0,k.jsxs)(`span`,{className:Q.codeFileMeta,children:[(rn.content||``).split(`
857
857
  `).length,` righe · `,iE(rn.content||``)]}),!rn._pending&&!rn._error&&rn.content&&(0,k.jsx)(`button`,{className:`${Q.editToggleBtn} ${C===null?``:Q.editToggleBtnActive}`,onClick:()=>{C===null?w(rn.content):(v(e=>e.map((e,t)=>t===y?{...e,content:C}:e)),E(`/api/studio/webcraft/file/write`,{projectName:c,path:rn.name,content:C}),w(null))},children:C===null?`✏ Modifica`:`💾 Salva`}),(0,k.jsx)(`button`,{className:Q.headerIconBtn,title:`Split view`,onClick:()=>ce(se===null?+(y===0&&g.length>1):null),children:`⫼`}),(0,k.jsx)(`button`,{className:`${Q.headerIconBtn} ${A?Q.headerIconBtnActive:``}`,title:`Terminal`,onClick:()=>oe(!A),children:`⌨`}),(0,k.jsx)(`button`,{className:Q.headerIconBtn,title:`Development Guide`,onClick:()=>ue(!0),children:`📖`})]}),ne&&(0,k.jsxs)(`div`,{className:Q.findBar,children:[(0,k.jsx)(`input`,{className:Q.findInput,value:D,onChange:e=>ie(e.target.value),placeholder:`Find...`,autoFocus:!0}),(0,k.jsx)(`input`,{className:Q.findInput,value:O,onChange:e=>ae(e.target.value),placeholder:`Replace...`}),(0,k.jsx)(`span`,{className:Q.findCount,children:D?((rn.content||``).match(new RegExp(D.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`gi`))?.length||0)+` found`:``}),(0,k.jsx)(`button`,{className:Q.findBtn,onClick:()=>{!D||C===null||w(C.replace(new RegExp(D.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`i`),O))},children:`Replace`}),(0,k.jsx)(`button`,{className:Q.findBtn,onClick:()=>{!D||C===null||w(C.replace(new RegExp(D.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`gi`),O))},children:`All`}),(0,k.jsx)(`button`,{className:Q.findClose,onClick:()=>re(!1),children:`×`})]}),rn._error&&(0,k.jsx)(`div`,{className:Q.fileError,children:`⚠ Generazione fallita — chiedi al modello di rigenerare questo file`}),rn._syntaxError&&!rn._error&&(0,k.jsxs)(`div`,{className:Q.fileSyntaxError,children:[`⚠ Syntax error: `,rn._syntaxError]}),N&&x!==null?(0,k.jsx)(`pre`,{className:Q.streamingPre,ref:e=>{e&&ge.current&&(e.scrollTop=e.scrollHeight)},onScroll:e=>{let t=e.currentTarget;t.scrollHeight-t.scrollTop-t.clientHeight<50?ge.current=!0:(ge.current=!1,_e.current&&clearTimeout(_e.current),_e.current=setTimeout(()=>{ge.current=!0},15e3))},dangerouslySetInnerHTML:{__html:QT(x||``,(rn.name.split(`.`).pop()||`js`).toLowerCase())+`<span class="`+Q.streamingCursor+`">▋</span>`}}):(0,k.jsx)(RT,{value:C===null?rn.content||``:C,filename:rn.name,readOnly:C===null,projectName:c,onChange:e=>{w(e),rn&&te(e=>new Set(e).add(rn.name))},onSave:e=>{v(t=>t.map((t,n)=>n===y?{...t,content:e}:t)),E(`/api/studio/webcraft/file/write`,{projectName:c,path:rn.name,content:e}),w(null),te(e=>{let t=new Set(e);return t.delete(rn.name),t})}})]})}),se!==null&&g[se]&&(0,k.jsxs)(`div`,{className:Q.codeEditorWrap,children:[(0,k.jsxs)(`div`,{className:Q.codeHeader,children:[(0,k.jsx)(`span`,{className:Q.codeFileIcon,children:rE(g[se].name)}),(0,k.jsx)(`span`,{className:Q.codeFileName,children:g[se].name}),(0,k.jsx)(`button`,{className:Q.headerIconBtn,onClick:()=>ce(null),children:`✕`})]}),(0,k.jsx)(RT,{value:g[se].content||``,filename:g[se].name,readOnly:!0})]})]}),A&&(0,k.jsxs)(`div`,{className:Q.terminalPanel,children:[(0,k.jsxs)(`div`,{className:Q.terminalHeader,children:[(0,k.jsx)(`span`,{className:Q.terminalTitle,children:`Terminal`}),(0,k.jsx)(`button`,{className:Q.terminalClose,onClick:()=>oe(!1),children:`✕`})]}),(0,k.jsx)(YT,{projectDir:c||void 0})]})]})})]})]})]})}),He&&t!==`projects`&&(0,k.jsxs)(`div`,{className:Q.planBanner,children:[(0,k.jsx)(`div`,{className:Q.planTitle,children:`📌 Piano proposto — approva per eseguire`}),(0,k.jsx)(`pre`,{className:Q.planText,children:He.plan}),(0,k.jsxs)(`div`,{className:Q.planActions,children:[(0,k.jsx)(`button`,{className:Q.planApprove,onClick:en,children:`✓ Esegui`}),(0,k.jsx)(`button`,{className:Q.planReject,onClick:()=>Ue(null),children:`✕ Annulla`})]})]}),Qe&&t!==`projects`&&(0,k.jsxs)(`div`,{className:Q.grepPanel,children:[(0,k.jsxs)(`div`,{className:Q.grepRow,children:[(0,k.jsx)(`input`,{className:Q.grepInput,value:et,onChange:e=>tt(e.target.value),onKeyDown:e=>e.key===`Enter`&&Kt(),placeholder:`Cerca nel codice...`}),(0,k.jsx)(`button`,{className:Q.grepBtn,onClick:Kt,children:`🔍`}),(0,k.jsx)(`button`,{className:Q.grepClose,onClick:()=>$e(!1),children:`×`})]}),nt.length>0&&(0,k.jsxs)(`div`,{className:Q.grepCount,children:[nt.length,` risultati`]}),(0,k.jsx)(`div`,{className:Q.grepResults,children:nt.length===0?(0,k.jsx)(`div`,{className:Q.grepEmpty,children:`Nessun risultato.`}):nt.map((e,t)=>(0,k.jsxs)(`div`,{className:Q.grepMatch,onClick:()=>qt(e.file),children:[(0,k.jsxs)(`span`,{className:Q.grepMatchFile,children:[e.file,`:`,e.lineNum]}),(0,k.jsx)(`pre`,{className:Q.grepMatchLine,children:e.line})]},t))})]}),it.length>0&&t!==`projects`&&(0,k.jsxs)(`div`,{className:Q.diffPanel,children:[(0,k.jsxs)(`div`,{className:Q.diffHeader,children:[(0,k.jsxs)(`span`,{children:[`🔌 Diff — `,it.length,` file modificati`]}),(0,k.jsx)(`button`,{className:Q.diffClose,onClick:()=>at([]),children:`✕ Chiudi`})]}),it.map((e,t)=>{let n=(e.after||``).split(`
858
858
  `).length-(e.before||``).split(`
859
859
  `).length;return(0,k.jsxs)(`details`,{open:!0,className:Q.diffFile,children:[(0,k.jsxs)(`summary`,{className:Q.diffSummary,children:[(0,k.jsx)(`span`,{className:Q.diffArrow,children:`▲`}),(0,k.jsx)(`span`,{className:Q.diffFileName,children:e.file}),(0,k.jsxs)(`span`,{className:n>=0?Q.diffAdded:Q.diffRemoved,children:[n>=0?`+`:``,n,` linee`]})]}),(0,k.jsx)(`div`,{className:Q.diffContent,children:(0,k.jsx)(uE,{before:e.before,after:e.after})})]},t)})]}),t!==`projects`&&(0,k.jsxs)(`div`,{className:`${Q.chatPanel} ${ut?Q.chatPanelCollapsed:``}`,children:[(0,k.jsxs)(`button`,{className:Q.chatCollapseBtn,onClick:()=>dt(e=>!e),children:[(0,k.jsx)(`span`,{children:ut?`▲`:`▼`}),(0,k.jsx)(`span`,{children:ut?`Show Chat`:`Hide Chat`}),Fe.length>0&&(0,k.jsxs)(`span`,{style:{opacity:.5},children:[`(`,Fe.length,`)`]})]}),(0,k.jsxs)(`div`,{className:Q.chatMessages,ref:Tt,children:[Fe.length===0&&nn&&(0,k.jsxs)(`div`,{className:Q.chatWelcome,children:[`🤖 `,e(`webcraft.doctrine.title`),` — `,(0,k.jsx)(`button`,{className:Q.doctrineOpenBtn,onClick:()=>ue(!0),children:`📖 Open Guide`})]}),Fe.map((e,t)=>(0,k.jsxs)(`div`,{className:e.role===`user`?Q.chatUser:e.role===`system`?Q.chatSystem:Q.chatAgent,children:[e.role===`user`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:Q.chatUserBubble,children:e.text}),e.attachments&&e.attachments.length>0&&(0,k.jsx)(`div`,{className:Q.chatAttachPreviews,children:e.attachments.map((e,t)=>(0,k.jsxs)(`span`,{className:Q.chatAttachBadge,children:[`📎 `,e.name]},t))})]}),e.role===`system`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:Q.chatSystemBubble,children:e.text}),e.syntaxErrors?.map((e,t)=>(0,k.jsxs)(`div`,{className:Q.chatSyntaxErr,children:[`✕ `,e.file,`: `,e.error]},t))]}),e.role===`agent`&&(()=>{let t=e.text.replace(/<tool>[\s\S]*?<\/tool>/g,``).replace(/<done\s*\/?>/g,``).trim(),n=(e.tools||[]).filter(e=>(e.op===`edit`||e.op===`write`)&&(e.result===`ok`||e.result===`ok_fuzzy`||e.result===`ok_repaired`)),r=(e.tools||[]).filter(e=>e.result?.includes(`not_found`)||e.result?.includes(`error`)||e.result===`blocked_use_edit`),a=t.match(/^(.{10,120}?)[.\n]/),o=a?a[1]+`.`:t.slice(0,120),s=t.length>130;return(0,k.jsxs)(`div`,{className:Q.chatAgentCard,children:[n.map((e,t)=>(0,k.jsxs)(`div`,{style:{margin:`6px 0`,borderRadius:8,overflow:`hidden`,border:`1px solid rgba(255,255,255,0.08)`},children:[(0,k.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,padding:`6px 10px`,background:`rgba(99,102,241,0.1)`,fontSize:11},children:[(0,k.jsxs)(`span`,{style:{fontWeight:600,color:`#818cf8`,cursor:`pointer`},onClick:()=>{let t=g.findIndex(t=>t.name===e.path);t>=0&&(b(t),i(`files`))},children:[`✏ `,e.path]}),(0,k.jsx)(`span`,{style:{color:`#4ade80`,fontSize:10,fontWeight:600},children:e.result===`ok_fuzzy`?`applied (fuzzy)`:e.result===`ok_repaired`?`applied (repaired)`:`✓ applied`})]}),e.oldSnippet||e.newSnippet?(0,k.jsx)(uE,{before:e.oldSnippet||``,after:e.newSnippet||``,contextLines:3}):(0,k.jsx)(`div`,{style:{padding:`6px 10px`,fontSize:11,color:`#4ade80`,background:`rgba(74,222,128,0.05)`},children:`File modified successfully`})]},t)),r.length>0&&(0,k.jsx)(`div`,{style:{margin:`6px 0`,padding:`6px 10px`,background:`rgba(248,113,113,0.08)`,borderRadius:6,fontSize:11,color:`#f87171`},children:r.map((e,t)=>(0,k.jsxs)(`div`,{children:[`❌ `,e.op,` `,e.path,`: `,typeof e.result==`string`?e.result.slice(0,100):``]},t))}),t&&(s?(0,k.jsxs)(`details`,{style:{margin:`6px 0`,fontSize:11},children:[(0,k.jsx)(`summary`,{style:{cursor:`pointer`,color:`var(--dim)`,padding:`4px 0`,userSelect:`none`},children:o.slice(0,100)}),(0,k.jsx)(`div`,{className:Q.chatAgentText,style:{fontSize:11,opacity:.8,marginTop:4},dangerouslySetInnerHTML:{__html:$T(t)}})]}):(0,k.jsx)(`div`,{className:Q.chatAgentText,style:{fontSize:11,opacity:.8},dangerouslySetInnerHTML:{__html:$T(t)}}))]})})()]},t)),ze&&(()=>{let e=Fe[Fe.length-1]?.tools??[],t=e[e.length-1],n=t?t.op===`read`?`Reading ${t.path}`:t.op===`edit`?`Editing ${t.path}`:t.op===`search`?`Searching...`:t.op===`lint`?`Linting ${t.path}`:t.op===`check`?`Checking ${t.path}`:t.op===`run`?`Running command...`:t.op===`sandbox`?`Starting sandbox...`:t.op:`Thinking...`;return(0,k.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8,padding:`8px 12px`,fontSize:12,color:`#818cf8`},children:[(0,k.jsx)(`span`,{className:Q.chatAgentRobotAnim,style:{fontSize:14},children:`⟳`}),(0,k.jsx)(`span`,{style:{fontWeight:500},children:n})]})})()]}),Be.length>0&&(0,k.jsx)(`div`,{className:Q.attachPreviews,children:Be.map((e,t)=>(0,k.jsxs)(`span`,{className:Q.attachBadge,children:[`📎 `,e.name,(0,k.jsx)(`button`,{className:Q.removeAttachBtn,onClick:()=>Ve(e=>e.filter((e,n)=>n!==t)),children:`×`})]},t))}),nn?(0,k.jsxs)(`div`,{className:Q.projActiveRow,children:[`📄 `,(0,k.jsx)(`strong`,{className:Q.projActiveName,children:c}),` — scrivi per modificare o migliorare il progetto`]}):(0,k.jsxs)(`div`,{className:Q.projNameRow,children:[(0,k.jsx)(`span`,{className:Q.projNameLabel,children:`Nome progetto:`}),(0,k.jsx)(`input`,{className:Q.projNameInput,value:c,onChange:e=>l(e.target.value),placeholder:`MioProgetto`})]}),(0,k.jsxs)(`div`,{className:Q.chatInputRow,children:[(0,k.jsxs)(`label`,{className:Q.attachLabel,title:`Allega immagine o PDF`,children:[`📎`,(0,k.jsx)(`input`,{ref:Et,type:`file`,multiple:!0,accept:`image/*,.pdf`,style:{display:`none`},onChange:e=>tn(e.target.files)})]}),(0,k.jsx)(`textarea`,{className:Q.chatTextarea,value:Le,onChange:e=>Re(e.target.value),placeholder:nn?`Parla con il tuo agente: chiedi correzioni, migliorie, nuove funzionalità...`:`Descrivi il progetto da creare, poi premi Genera...`,disabled:U,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),Pt())},rows:4}),(0,k.jsxs)(`div`,{className:Q.chatSendCol,children:[(0,k.jsx)(`button`,{className:Q.chatSendBtn,onClick:()=>Pt(),disabled:U,children:N?`⏳`:nn?`▶`:`▶ Genera`}),U&&!we&&(0,k.jsx)(`button`,{className:Q.chatStopBtn,onClick:Lt,children:`⏹ Stop`})]})]})]}),le&&(0,k.jsx)(`div`,{className:Q.modalOverlay,onClick:()=>ue(!1),children:(0,k.jsxs)(`div`,{className:Q.modal,onClick:e=>e.stopPropagation(),style:{width:720,maxHeight:`90vh`},children:[(0,k.jsxs)(`div`,{className:Q.modalHeader,children:[(0,k.jsxs)(`span`,{className:Q.modalTitle,children:[`📖 `,e(`webcraft.doctrine.title`)]}),(0,k.jsx)(`span`,{className:Q.doctrineSubtitle,children:e(`webcraft.doctrine.subtitle`)}),(0,k.jsx)(`button`,{className:Q.modalClose,onClick:()=>ue(!1),children:`✕`})]}),(0,k.jsx)(`div`,{className:Q.modalBody,style:{gap:0},children:[`phase1`,`phase2`,`phase3`,`phase4`,`phase5`,`tools`,`golden`].map(t=>(0,k.jsxs)(`div`,{className:Q.doctrineSection,children:[(0,k.jsx)(`div`,{className:Q.doctrineSectionTitle,children:e(`webcraft.doctrine.${t}.title`)}),(0,k.jsx)(`div`,{className:Q.doctrineSectionBody,children:e(`webcraft.doctrine.${t}.desc`).split(`
@@ -8,7 +8,7 @@
8
8
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
9
9
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10
10
  <title>NHA — NotHumanAllowed</title>
11
- <script type="module" crossorigin src="/assets/index-DfKlqTu1.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-Dy-GFsjK.js"></script>
12
12
  <link rel="stylesheet" crossorigin href="/assets/index-nUBdqB1O.css">
13
13
  </head>
14
14
  <body>