nothumanallowed 14.5.9 → 14.5.10

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": "14.5.9",
3
+ "version": "14.5.10",
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/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 = '14.5.9';
8
+ export const VERSION = '14.5.10';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -603,7 +603,7 @@ const ChatStore = {
603
603
  * Tool-calling agent that can read/edit/write files inside the project.
604
604
  * Uses structured SSE events: { type: 'text', token } | { type: 'tool', ... } | { type: 'done', changed }
605
605
  */
606
- async function runWebCraftAgent(config, projectName, message, attachments, emit) {
606
+ async function runWebCraftAgent(config, projectName, message, attachments, emit, isAborted = () => false) {
607
607
  const MAX_STEPS = 8; // max agentic loop iterations
608
608
  const dir = ProjectStore.dir(projectName);
609
609
  if (!fs.existsSync(dir)) { emit({ type: 'error', msg: 'Project not found' }); return; }
@@ -740,6 +740,7 @@ RULES:
740
740
  ];
741
741
 
742
742
  for (let step = 0; step < MAX_STEPS; step++) {
743
+ if (isAborted()) break;
743
744
  const systemPrompt = buildSystemPrompt();
744
745
  emit({ type: 'step', step: step + 1, max: MAX_STEPS });
745
746
 
@@ -878,15 +879,18 @@ RULES:
878
879
  toolResults.push({ op: 'write', path: relPath, result: 'missing_content' });
879
880
  emit({ type: 'tool', op: 'write', path: relPath, result: 'missing_content' });
880
881
  } else {
881
- // Capture previous content for diff
882
882
  const prevContent = ProjectStore.readFile(projectName, relPath);
883
- ProjectStore.writeFile(projectName, relPath, content);
884
- hasChanges = true;
885
- modifiedFiles.add(relPath);
886
- const oldSnippet = prevContent ? prevContent.slice(0, 500) : '';
887
- const newSnippet = content.slice(0, 500);
888
- toolResults.push({ op: 'write', path: relPath, result: 'ok', oldSnippet, newSnippet });
889
- emit({ type: 'tool', op: 'write', path: relPath, result: 'ok', oldSnippet, newSnippet });
883
+ // BLOCK: if file already exists, reject write and force edit
884
+ if (prevContent !== null) {
885
+ toolResults.push({ op: 'write', path: relPath, result: 'error: file already exists — use edit tool to make surgical changes, do NOT rewrite the entire file. Read the file first, then use edit with exact old/new strings.' });
886
+ emit({ type: 'tool', op: 'write', path: relPath, result: 'blocked_use_edit' });
887
+ } else {
888
+ ProjectStore.writeFile(projectName, relPath, content);
889
+ hasChanges = true;
890
+ modifiedFiles.add(relPath);
891
+ toolResults.push({ op: 'write', path: relPath, result: 'ok' });
892
+ emit({ type: 'tool', op: 'write', path: relPath, result: 'ok', newSnippet: content.slice(0, 500) });
893
+ }
890
894
  }
891
895
 
892
896
  // ── rename ──
@@ -2439,13 +2443,22 @@ export function register(router) {
2439
2443
  const { projectName, message, attachments = [] } = body;
2440
2444
  if (!projectName || !message) return sendError(res, 400, 'projectName and message required');
2441
2445
 
2446
+ // Abort detection — stop agent when client disconnects
2447
+ let clientAborted = false;
2448
+ req.on('close', () => { clientAborted = true; });
2449
+ req.on('aborted', () => { clientAborted = true; });
2450
+
2442
2451
  const sse = sendSSE(res);
2452
+ const guardedEmit = (ev) => {
2453
+ if (clientAborted || res.writableEnded) return;
2454
+ sse.send(ev);
2455
+ };
2443
2456
  try {
2444
- await runWebCraftAgent(config, projectName, message, attachments, sse.send);
2457
+ await runWebCraftAgent(config, projectName, message, attachments, guardedEmit, () => clientAborted);
2445
2458
  } catch (e) {
2446
- sse.send({ type: 'error', msg: e.message });
2459
+ if (!clientAborted) sse.send({ type: 'error', msg: e.message });
2447
2460
  }
2448
- sse.end();
2461
+ if (!res.writableEnded) sse.end();
2449
2462
  });
2450
2463
 
2451
2464
  // ── Autofix queue ─────────────────────────────────────────────────────────
@@ -766,13 +766,13 @@ FRONTEND:
766
766
  - apply.html: Application modal/page — job summary header, form (Full Name / Email / Phone / LinkedIn URL / Portfolio URL / Cover Letter textarea with character count / Resume paste textarea), Submit button with loading state, success page with application reference number
767
767
  - public/css/main.css: Modern job board design — tag/badge system (Remote=blue, Onsite=green, Urgent=red), salary range display, company logo placeholder styles, filter sidebar collapse on mobile, job card hover effects, application form validation styles`}],BT=[{key:`auth`,label:`Auth (register/login/JWT)`,icon:`🔒`},{key:`cookieBanner`,label:`GDPR Cookie Banner`,icon:`🍪`},{key:`securityMiddleware`,label:`Security Middleware`,icon:`🛡️`},{key:`emailVerification`,label:`Email Verification`,icon:`✉️`}],VT={js:`📄`,ts:`📄`,css:`🎨`,html:`🌐`,json:`📋`,md:`📑`,sql:`🗂`,env:`🔐`,conf:`⚙`,lock:`🔒`};function HT(e){return VT[e.split(`.`).pop()?.toLowerCase()??``]??`📄`}function UT(e){let t=new TextEncoder().encode(e).length;return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(2)} MB`}function WT(e){return e===`memory`?`🧠`:e===`provider`?`🤖`:e===`log`?`📄`:`📋`}function GT(){let e=j(),[t,n]=(0,_.useState)(`new`),[r,i]=(0,_.useState)(`files`),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)({auth:!0,cookieBanner:!0,securityMiddleware:!0,emailVerification:!0}),[d,f]=(0,_.useState)([{label:`Email`,type:`email`,required:!0},{label:`Password`,type:`password`,required:!0},{label:`Name`,type:`text`,required:!0}]),[p,m]=(0,_.useState)([]),[h,g]=(0,_.useState)(0),[v,y]=(0,_.useState)(null),[b,x]=(0,_.useState)(null),[S,C]=(0,_.useState)(new Set),[w,ee]=(0,_.useState)(!1),[te,T]=(0,_.useState)(``),[ne,re]=(0,_.useState)(``),[ie,O]=(0,_.useState)(!1),[ae,A]=(0,_.useState)(null),[oe,se]=(0,_.useState)(!1),[ce,le]=(0,_.useState)([]),[ue,de]=(0,_.useState)([]),M=(0,_.useRef)(null),fe=(0,_.useRef)(null),pe=(0,_.useRef)(!0),me=(0,_.useRef)(null),he=(0,_.useRef)(null),ge=(0,_.useRef)(null),_e=(0,_.useRef)(null),[ve,ye]=(0,_.useState)(null),[be,xe]=(0,_.useState)(!1),[Se,N]=(0,_.useState)(!1),[Ce,we]=(0,_.useState)(0),[Te,Ee]=(0,_.useState)(0),[P,De]=(0,_.useState)(``),[Oe,ke]=(0,_.useState)({fi:0,total:0,name:``}),[F,I]=(0,_.useState)({tokIn:0,tokOut:0}),[Ae,je]=(0,_.useState)(null),[Me,Ne]=(0,_.useState)([]),[Pe,Fe]=(0,_.useState)(``),[Ie,Le]=(0,_.useState)(!1),[Re,ze]=(0,_.useState)([]),[L,Be]=(0,_.useState)(null),[Ve,He]=(0,_.useState)([]),[Ue,We]=(0,_.useState)(!1),[Ge,Ke]=(0,_.useState)(null),[qe,Je]=(0,_.useState)([]),[Ye,Xe]=(0,_.useState)(!1),[Ze,Qe]=(0,_.useState)(``),[$e,et]=(0,_.useState)([]),[tt,nt]=(0,_.useState)([]),[rt,it]=(0,_.useState)([]),[at,ot]=(0,_.useState)(null),[st,ct]=(0,_.useState)(!1),[lt,ut]=(0,_.useState)(null),[dt,ft]=(0,_.useState)(`0s`),[R,pt]=(0,_.useState)(`0s`),mt=(0,_.useRef)(0),ht=(0,_.useRef)(0),gt=(0,_.useRef)(null),_t=(0,_.useRef)(null),vt=(0,_.useRef)(null),yt=(0,_.useRef)(null),z=(0,_.useRef)(null),bt=(0,_.useRef)(!1),xt=(0,_.useRef)(null);function St(e){D(`/api/studio/webcraft/scan`,{projectName:e}).then(e=>{if(e?.issues)if(de(e.issues),e.issues.length>0){let t=new Set(e.issues.filter(e=>e.severity===`error`).map(e=>e.file));m(n=>n.map(n=>{if(t.has(n.name)){let t=e.issues.filter(e=>e.file===n.name);return{...n,_syntaxError:t.map(e=>e.message).join(`; `)}}return{...n,_syntaxError:void 0,_error:!1}}))}else m(e=>e.map(e=>({...e,_syntaxError:void 0,_error:!1})))}).catch(()=>{})}(0,_.useEffect)(()=>{if(!at){le([]);return}let e=setInterval(()=>{E(`/api/studio/webcraft/sandbox/errors`).then(e=>{e?.errors?.length&&le(e.errors)}).catch(()=>{})},5e3);return()=>clearInterval(e)},[at]);let Ct=(0,_.useRef)(at);Ct.current=at,(0,_.useEffect)(()=>{let e=()=>{Ct.current&&(navigator.sendBeacon(`/api/studio/webcraft/sandbox/stop-beacon`,``),fetch(`/api/studio/webcraft/sandbox`,{method:`DELETE`,keepalive:!0}).catch(()=>{}))};return window.addEventListener(`beforeunload`,e),()=>{window.removeEventListener(`beforeunload`,e),e()}},[]),(0,_.useEffect)(()=>{let e=e=>{if((e.metaKey||e.ctrlKey)&&e.key===`f`&&(e.preventDefault(),ee(e=>!e)),(e.metaKey||e.ctrlKey)&&e.key===`s`&&(e.preventDefault(),b!==null&&p[h])){let e=p[h];m(e=>e.map((e,t)=>t===h?{...e,content:b}:e)),D(`/api/studio/webcraft/file/write`,{projectName:a,path:e.name,content:b}),x(null),C(t=>{let n=new Set(t);return n.delete(e.name),n})}};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[b,h,p,a]),(0,_.useEffect)(()=>{let e=()=>{let e=b===null?ge.current:he.current;e&&_e.current&&(_e.current.scrollTop=e.scrollTop)},t=b===null?ge.current:he.current;return t&&t.addEventListener(`scroll`,e),()=>{t&&t.removeEventListener(`scroll`,e)}},[b,h]);function wt(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function B(e){let t=Math.floor((Date.now()-e)/1e3),n=Math.floor(t/60);return(n>0?`${n}m `:``)+`${t%60}s`}(0,_.useEffect)(()=>(be||Se?gt.current=setInterval(()=>{be&&ft(B(mt.current)),Se&&pt(B(ht.current))},1e3):gt.current&&=(clearInterval(gt.current),null),()=>{gt.current&&clearInterval(gt.current)}),[be,Se]);function Tt(){vt.current&&(vt.current.scrollTop=vt.current.scrollHeight)}(0,_.useEffect)(()=>{Tt()},[Me]),(0,_.useEffect)(()=>{a&&!Ue&&(We(!0),E(`/api/studio/webcraft/skills/${encodeURIComponent(a)}`).then(e=>{e?.skills&&He(e.skills)}).catch(()=>{}))},[a,Ue]);async function Et(e,t){if(be||!e||e.length<5)return;xe(!0),m([]),g(0),y(null),ke({fi:0,total:0,name:``}),I({tokIn:0,tokOut:0}),mt.current=Date.now(),ft(`0s`),_t.current=new AbortController;let n=Date.now();try{let r=await fetch(`/api/studio/webcraft/generate`,{method:`POST`,headers:{"Content-Type":`application/json`},signal:_t.current.signal,body:JSON.stringify({projectName:t,description:e,blocks:l,authFields:d})});if(!r.ok||!r.body){xe(!1);return}let i=r.body.getReader(),s=_t.current,c=new TextDecoder,u=``,f=[];for(;;){if(s?.signal?.aborted){try{i.cancel()}catch{}break}let{done:e,value:t}=await i.read();if(e)break;u+=c.decode(t,{stream:!0});let r=u.split(`
768
768
 
769
- `);u=r.pop()??``;for(let e of r){let t=e.replace(/^data: /,``).trim();if(t)try{let e=JSON.parse(t);if(e.type===`project_renamed`)o(e.name);else if(e.type===`processing`||e.type===`planning`)ke(t=>({...t,name:e.type===`planning`?`📋 Pianificazione struttura...`:e.msg||`Avvio...`}));else if(e.type===`file_start`)f.push({name:e.name,content:``,_pending:!0}),m([...f]),ke({fi:e.fi,total:e.total,name:e.name}),M.current=f.length-1,fe.current||(g(f.length-1),y(``)),pe.current=!0;else if(e.type===`file_chunk`){let t=f.find(t=>t.name===e.name);t&&(t.content+=e.chunk,t._pending=!1),m([...f]);let n=f.findIndex(t=>t.name===e.name);n>=0&&(M.current=n,y(t?t.content:null))}else if(e.type===`file_done`){let t=f.find(t=>t.name===e.name);t&&(t._pending=!1,e.syntaxError&&(t._syntaxError=e.syntaxError)),m([...f]),ke({fi:e.fi,total:e.total,name:e.name}),(e.cumTokIn||e.cumTokOut)&&I({tokIn:e.cumTokIn||0,tokOut:e.cumTokOut||0})}else if(e.type===`file_error`){let t=f.find(t=>t.name===e.name);t&&(t._error=!0,t._pending=!1),m([...f])}else e.type===`phase`||e.type===`status`&&!e.op?ke(t=>({...t,name:e.msg||e.phase||``})):e.type===`done`&&(je({seconds:Math.round((Date.now()-n)/1e3),tokIn:e.tokIn??0,tokOut:e.tokOut??0,files:f.length}),y(null),xe(!1),M.current=null,fe.current&&=(clearTimeout(fe.current),null),a&&St(a),se(!0),We(!1),He([]),f.some(e=>e._error||e._syntaxError)?setTimeout(()=>z.current?.(),800):setTimeout(()=>xt.current?.(),800))}catch{}}}}catch(e){e.name!==`AbortError`&&Ne(t=>[...t,{role:`system`,text:`Errore generazione: `+e.message}]),xe(!1)}}async function Dt(){let e=Pe.trim();if(!(a&&p.length>0)){if(!e||e.length<5)return;let t=a||`MyProject`;o(t),c(e),Fe(``),await Et(e,t);return}if(!e&&Re.length===0||Ie||be)return;let t=[...Re];if(ze([]),Fe(``),e.toLowerCase().startsWith(`/plan `)||e.toLowerCase().startsWith(`piano: `)){let t=e.replace(/^\/plan[ ]*/i,``).replace(/^piano:[ ]*/i,``);Ne(t=>[...t,{role:`user`,text:e}]),await Ot(`[MODALITA PIANO] Descrivi cosa modificheresti per: "${t}". Elenca i file e cosa faresti. NON applicare modifiche ancora. Rispondi con il piano in bullet list.`,t,[]);return}Ne(n=>[...n,{role:`user`,text:e,attachments:t}]),await Ot(e,null,t)}async function Ot(e,t,n){if(Ie)return;Le(!0),a&&p.length>0&&D(`/api/studio/webcraft/snapshot`,{projectName:a}).catch(()=>{});let r={};p.forEach(e=>{r[e.name]=e.content});try{let i=await fetch(`/api/studio/webcraft/agent`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectName:a,message:e,attachments:n.map(e=>({name:e.name,mimeType:e.mimeType,base64:e.base64}))})});if(!i.ok||!i.body){Ne(e=>[...e,{role:`agent`,text:`Errore: ${i.status}`,tools:[]}]),Le(!1);return}let o={role:`agent`,text:``,tools:[]};Ne(e=>[...e,o]);let s=i.body.getReader(),c=new TextDecoder,l=``,u=!1,d=``;for(;;){let{done:e,value:n}=await s.read();if(e)break;l+=c.decode(n,{stream:!0});let i=l.split(`
769
+ `);u=r.pop()??``;for(let e of r){let t=e.replace(/^data: /,``).trim();if(t)try{let e=JSON.parse(t);if(e.type===`project_renamed`)o(e.name);else if(e.type===`processing`||e.type===`planning`)ke(t=>({...t,name:e.type===`planning`?`📋 Pianificazione struttura...`:e.msg||`Avvio...`}));else if(e.type===`file_start`)f.push({name:e.name,content:``,_pending:!0}),m([...f]),ke({fi:e.fi,total:e.total,name:e.name}),M.current=f.length-1,fe.current||(g(f.length-1),y(``)),pe.current=!0;else if(e.type===`file_chunk`){let t=f.find(t=>t.name===e.name);t&&(t.content+=e.chunk,t._pending=!1),m([...f]);let n=f.findIndex(t=>t.name===e.name);n>=0&&(M.current=n,y(t?t.content:null))}else if(e.type===`file_done`){let t=f.find(t=>t.name===e.name);t&&(t._pending=!1,e.syntaxError&&(t._syntaxError=e.syntaxError)),m([...f]),ke({fi:e.fi,total:e.total,name:e.name}),(e.cumTokIn||e.cumTokOut)&&I({tokIn:e.cumTokIn||0,tokOut:e.cumTokOut||0})}else if(e.type===`file_error`){let t=f.find(t=>t.name===e.name);t&&(t._error=!0,t._pending=!1),m([...f])}else e.type===`phase`||e.type===`status`&&!e.op?ke(t=>({...t,name:e.msg||e.phase||``})):e.type===`done`&&(je({seconds:Math.round((Date.now()-n)/1e3),tokIn:e.tokIn??0,tokOut:e.tokOut??0,files:f.length}),y(null),xe(!1),M.current=null,fe.current&&=(clearTimeout(fe.current),null),a&&St(a),se(!0),We(!1),He([]),f.some(e=>e._error||e._syntaxError)?setTimeout(()=>z.current?.(),800):setTimeout(()=>xt.current?.(),800))}catch{}}}}catch(e){e.name!==`AbortError`&&Ne(t=>[...t,{role:`system`,text:`Errore generazione: `+e.message}]),xe(!1)}}async function Dt(){let e=Pe.trim();if(!(a&&p.length>0)){if(!e||e.length<5)return;let t=a||`MyProject`;o(t),c(e),Fe(``),await Et(e,t);return}if(!e&&Re.length===0||Ie||be)return;let t=[...Re];if(ze([]),Fe(``),e.toLowerCase().startsWith(`/plan `)||e.toLowerCase().startsWith(`piano: `)){let t=e.replace(/^\/plan[ ]*/i,``).replace(/^piano:[ ]*/i,``);Ne(t=>[...t,{role:`user`,text:e}]),await Ot(`[MODALITA PIANO] Descrivi cosa modificheresti per: "${t}". Elenca i file e cosa faresti. NON applicare modifiche ancora. Rispondi con il piano in bullet list.`,t,[]);return}Ne(n=>[...n,{role:`user`,text:e,attachments:t}]),await Ot(e,null,t)}async function Ot(e,t,n){if(Ie)return;Le(!0),a&&p.length>0&&D(`/api/studio/webcraft/snapshot`,{projectName:a}).catch(()=>{});let r={};p.forEach(e=>{r[e.name]=e.content});try{let i=new AbortController;_t.current=i;let o=await fetch(`/api/studio/webcraft/agent`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectName:a,message:e,attachments:n.map(e=>({name:e.name,mimeType:e.mimeType,base64:e.base64}))}),signal:i.signal});if(!o.ok||!o.body){Ne(e=>[...e,{role:`agent`,text:`Errore: ${o.status}`,tools:[]}]),Le(!1);return}let s={role:`agent`,text:``,tools:[]};Ne(e=>[...e,s]);let c=o.body.getReader(),l=new TextDecoder,u=``,d=!1,f=``;for(;;){if(i.signal.aborted){try{c.cancel()}catch{}break}let{done:e,value:n}=await c.read();if(e)break;u+=l.decode(n,{stream:!0});let a=u.split(`
770
770
 
771
- `);l=i.pop()??``;for(let e of i){let n=e.replace(/^data: /,``).trim();if(n)try{let e=JSON.parse(n);if(e.type===`text`){d+=e.token;let t=d.lastIndexOf(`<`),n;t>=0&&!d.slice(t).includes(`>`)?(n=d.slice(0,t),d=d.slice(t)):(n=d.replace(/<tool>[\s\S]*?<\/tool>/g,``).replace(/<done\s*\/>/g,``),d=``),n&&(o.text+=n,Ne(e=>{let t=[...e];return t[t.length-1]={...o},t}))}else if(e.type===`step`)o.text+=`\n\n**[Step ${e.step}/${e.max}]** `,Ne(e=>{let t=[...e];return t[t.length-1]={...o},t});else if(e.type===`tool`)o.tools.push({op:e.op,path:e.path,result:e.result,oldSnippet:e.oldSnippet??``,newSnippet:e.newSnippet??``}),(e.op===`edit`||e.op===`write`)&&(e.result===`ok`||e.result===`ok_repaired`)&&(u=!0),Ne(e=>{let t=[...e];return t[t.length-1]={...o},t});else if(e.type===`files_changed`)e.files?.length&&await kt(e.files,r);else if(e.type===`syntax_errors`)e.errors?.length&&(o.syntaxErrors=e.errors,Ne(e=>{let t=[...e];return t[t.length-1]={...o},t}));else if(e.type===`sandbox_restart`)o.text+=`
771
+ `);u=a.pop()??``;for(let e of a){let n=e.replace(/^data: /,``).trim();if(n)try{let e=JSON.parse(n);if(e.type===`text`){f+=e.token;let t=f.lastIndexOf(`<`),n;t>=0&&!f.slice(t).includes(`>`)?(n=f.slice(0,t),f=f.slice(t)):(n=f.replace(/<tool>[\s\S]*?<\/tool>/g,``).replace(/<done\s*\/>/g,``),f=``),n&&(s.text+=n,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t}))}else if(e.type===`step`)s.text+=`\n\n**[Step ${e.step}/${e.max}]** `,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t});else if(e.type===`tool`){s.tools.push({op:e.op,path:e.path,result:e.result,oldSnippet:e.oldSnippet??``,newSnippet:e.newSnippet??``}),(e.op===`edit`||e.op===`write`)&&(e.result===`ok`||e.result===`ok_repaired`)&&(d=!0);let t=e.op===`read`?`📖 Read`:e.op===`edit`?`✏️ Edit`:e.op===`write`?`📝 Write`:e.op===`search`?`🔍 Search`:e.op===`lint`?`🔬 Lint`:e.op===`check`?`✓ Check`:e.op===`run`?`▶ Run`:e.op===`sandbox`?`🌐 Sandbox`:e.op===`delete`?`🗑 Delete`:e.op===`rename`?`📋 Rename`:e.op===`list`?`📁 List`:e.op===`diff`?`🔀 Diff`:e.op,n=e.result===`ok`||e.result===`ok_repaired`?`✅`:e.result?.startsWith(`error`)||e.result===`blocked_use_edit`?`❌`:`⚡`;s.text+=`\n${t} \`${e.path||``}\` ${n}`,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t})}else if(e.type===`files_changed`)e.files?.length&&await kt(e.files,r);else if(e.type===`syntax_errors`)e.errors?.length&&(s.syntaxErrors=e.errors,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t}));else if(e.type===`sandbox_restart`)s.text+=`
772
772
 
773
- 🔄 `+(e.msg||`Restarting sandbox...`),Ne(e=>{let t=[...e];return t[t.length-1]={...o},t});else if(e.type===`sandbox_ready`)ot(e.port),o.text+=`
774
- ✅ Sandbox ready on port `+e.port,Ne(e=>{let t=[...e];return t[t.length-1]={...o},t});else if(e.type===`sandbox_error`)o.text+=`
775
- ❌ Sandbox error: `+e.msg,Ne(e=>{let t=[...e];return t[t.length-1]={...o},t});else if(e.type===`done`){if(d){let e=d.replace(/<tool>[\s\S]*?<\/tool>/g,``).replace(/<done\s*\/>/g,``);e&&(o.text+=e),d=``}t&&!u&&Be({plan:o.text,originalMessage:t}),Le(!1),e.changed&&await kt((o.tools??[]).filter(e=>e.op===`edit`||e.op===`write`).map(e=>e.path),r)}else e.type===`error`&&(o.text+=`
773
+ 🔄 `+(e.msg||`Restarting sandbox...`),Ne(e=>{let t=[...e];return t[t.length-1]={...s},t});else if(e.type===`sandbox_ready`)ot(e.port),s.text+=`
774
+ ✅ Sandbox ready on port `+e.port,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t});else if(e.type===`sandbox_error`)s.text+=`
775
+ ❌ Sandbox error: `+e.msg,Ne(e=>{let t=[...e];return t[t.length-1]={...s},t});else if(e.type===`done`){if(f){let e=f.replace(/<tool>[\s\S]*?<\/tool>/g,``).replace(/<done\s*\/>/g,``);e&&(s.text+=e),f=``}t&&!d&&Be({plan:s.text,originalMessage:t}),Le(!1),e.changed&&await kt((s.tools??[]).filter(e=>e.op===`edit`||e.op===`write`).map(e=>e.path),r)}else e.type===`error`&&(s.text+=`
776
776
  Errore: `+e.msg,Le(!1))}catch{}}}}catch(e){Ne(t=>[...t,{role:`agent`,text:`Errore di rete: `+e.message,tools:[]}])}Le(!1)}async function kt(e,t){if(!a)return;let n=await E(`/api/studio/webcraft/projects/load/${encodeURIComponent(a)}`);if(n?.files&&(m(n.files),a&&St(a),e.length>0)){let r=e.map(e=>{let r=n.files.find(t=>t.name===e);return r?{file:e,before:t[e]??``,after:r.content}:null}).filter(Boolean);nt(e=>[...e,...r])}}function At(){_t.current&&=(_t.current.abort(),null),bt.current=!0,xe(!1),Le(!1),N(!1),De(``),y(null),Ne(e=>[...e,{role:`system`,text:`⏹ Generazione interrotta.`}])}async function jt(){return a?(await D(`/api/studio/webcraft/snapshot`,{projectName:a}))?.snapshot??null:null}async function Mt(){let e=await jt();e&&(Ne(t=>[...t,{role:`system`,text:`💾 Snapshot salvato (${e.slice(0,16).replace(`T`,` `)})`}]),Nt())}async function Nt(){if(!a)return;let e=await E(`/api/studio/webcraft/snapshots/${encodeURIComponent(a)}`);e?.snapshots&&Je(e.snapshots)}async function V(e){confirm(`Ripristinare lo snapshot del ${e.replace(`T`,` `).slice(0,16)}? I file attuali verranno sovrascritti.`)&&await D(`/api/studio/webcraft/restore`,{projectName:a,ts:e})!==null&&(Ne(t=>[...t,{role:`agent`,text:`Snapshot ripristinato (${e}). Ricarico i file...`}]),kt([],{}))}async function Pt(){if(!a)return;let e=await D(`/api/studio/webcraft/syntax-check`,{projectName:a});if(e?.results){let t=e.results.filter(e=>!e.ok);t.length>0?Ne(e=>[...e,{role:`system`,text:`⚠ Syntax check: ${t.length} errore/i trovato/i.`,syntaxErrors:t}]):Ne(e=>[...e,{role:`system`,text:`✓ Syntax check: tutti i file JS sono validi.`}])}}async function Ft(){let e=p.filter(e=>e._error||e._syntaxError);if(e.length===0){xt.current?.();return}bt.current=!1,N(!0),we(0),Ee(e.length),ht.current=Date.now(),pt(`0s`);for(let t=0;t<e.length&&!bt.current;t++){let n=e[t];De(n.name),we(t);let r=`FIX ERROR in ${n.name}: ${n._syntaxError??`generazione fallita`}\n\nUse the edit tool to make surgical fixes. Do NOT rewrite the entire file — only change the broken parts. Read the file first, identify the exact lines with errors, and edit only those lines.`;try{await Ot(r,null,[])}catch{if(bt.current)break}}bt.current||(we(e.length),setTimeout(()=>xt.current?.(),500)),De(``),N(!1)}async function It(e){if(!st){ct(!0),ut(null),ot(null),i(`preview`);try{let t=await fetch(`/api/studio/webcraft/sandbox/start`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectName:e})});if(!t.ok||!t.body){ut(t.ok?`No response body`:`HTTP ${t.status}`),ct(!1);return}let n=t.body.getReader(),r=new TextDecoder,i=``;for(;;){let{done:e,value:t}=await n.read();if(e)break;i+=r.decode(t,{stream:!0});let a=i.split(`
777
777
 
778
778
  `);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===`ready`&&e.port?(ot(e.port),ct(!1)):e.type===`status`||e.type===`log`||e.type===`warn`||(e.type===`error`?ut(e.msg):e.type))}catch{}}}}catch(e){ut(e.message||`Connection failed`)}ct(!1)}}async function Lt(){a&&await It(a)}(0,_.useEffect)(()=>{z.current=Ft,xt.current=Lt});async function Rt(){if(!Ze||!a)return;let e=await D(`/api/studio/webcraft/grep`,{projectName:a,query:Ze});e?.matches&&et(e.matches)}function zt(e){let t=p.findIndex(t=>t.name===e);t>=0&&(g(t),i(`files`))}function Bt(){window.open(`/api/studio/webcraft/download/${encodeURIComponent(a)}`,`_blank`)}async function H(e,t,n,r){t.endsWith(`.md`)||(t+=`.md`);let i={name:t,content:n,type:r},s;s=e.mode===`edit`&&e.idx!==null?Ve.map((t,n)=>n===e.idx?i:t):[...Ve,i],He(s),Ke(null);let c=a||`MyProject`;a||o(c),await D(`/api/studio/webcraft/skills/${encodeURIComponent(c)}`,{skills:s})}async function Vt(e){let t=Ve[e];!t||!confirm(`Eliminare "${t.name}"?`)||(await D(`/api/studio/webcraft/skills/${encodeURIComponent(a)}/delete`,{name:t.name}),He(Ve.filter((t,n)=>n!==e)))}async function Ht(e){let t=Ve[e];if(!t||!confirm(`Svuotare "${t.name}"? Il file rimane ma il contenuto viene cancellato.`))return;let n=Ve.map((t,n)=>n===e?{...t,content:``}:t);He(n),await D(`/api/studio/webcraft/skills/${encodeURIComponent(a)}`,{skills:n})}async function Ut(){let e=await E(`/api/studio/webcraft/projects`);e?.projects&&it(e.projects)}async function Wt(e){let t=await E(`/api/studio/webcraft/projects/load/${encodeURIComponent(e.name)}`);if(!t)return;let r=t.projectName??e.name;o(r),c(t.description??``),m(t.files??[]),g(0),n(`new`),i(`files`),Ne([]),He([]),We(!1),de([]),St(r);let a=await E(`/api/studio/webcraft/projects/chat/load/${encodeURIComponent(r)}`);a?.chat&&Ne(a.chat);let s=await E(`/api/studio/webcraft/skills/${encodeURIComponent(r)}`);s?.skills&&(He(s.skills),We(!0))}async function Gt(e){confirm(`Eliminare: ${e.name} - ${e.dir}?`)&&(await D(`/api/studio/webcraft/projects/${encodeURIComponent(e.name)}`,{},`DELETE`),it(rt.filter(t=>t.name!==e.name)),a===e.name&&(o(``),m([]),Ne([]),c(``)))}async function U(){if(!L)return;let e=L.originalMessage;Be(null),await Ot(e+`
@@ -781,7 +781,7 @@ Errore: `+e.msg,Le(!1))}catch{}}}}catch(e){Ne(t=>[...t,{role:`agent`,text:`Error
781
781
  `)}`),i(`files`)},children:`Fix`})]}),(0,k.jsx)(jT,{files:p,activeIndex:h,unsavedFiles:S,onSelect:e=>{g(e),x(null),y(null),be&&M.current!==null&&e!==M.current&&(fe.current&&clearTimeout(fe.current),fe.current=setTimeout(()=>{M.current!==null&&(g(M.current),y(null))},1e4))}})]}),(0,k.jsx)(`div`,{className:$.codeEditorWrap,children:Jt&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:$.codeHeader,children:[(0,k.jsx)(`span`,{className:$.codeFileIcon,children:HT(Jt.name)}),(0,k.jsx)(`span`,{className:$.codeFileName,children:Jt.name}),Jt.content&&!Jt._error&&(0,k.jsxs)(`span`,{className:$.codeFileMeta,children:[Jt.content.split(`
782
782
  `).length,` righe · `,UT(Jt.content)]}),!Jt._pending&&!Jt._error&&Jt.content&&(0,k.jsx)(`button`,{className:`${$.editToggleBtn} ${b===null?``:$.editToggleBtnActive}`,onClick:()=>{b===null?x(Jt.content):(m(e=>e.map((e,t)=>t===h?{...e,content:b}:e)),D(`/api/studio/webcraft/file/write`,{projectName:a,path:Jt.name,content:b}),x(null))},children:b===null?`✏ Modifica`:`💾 Salva`}),(0,k.jsx)(`button`,{className:$.headerIconBtn,title:`Split view`,onClick:()=>A(ae===null?+(h===0&&p.length>1):null),children:`⫼`}),(0,k.jsx)(`button`,{className:`${$.headerIconBtn} ${ie?$.headerIconBtnActive:``}`,title:`Terminal`,onClick:()=>O(!ie),children:`⌨`}),(0,k.jsx)(`button`,{className:$.headerIconBtn,title:`Development Guide`,onClick:()=>se(!0),children:`📖`})]}),w&&(0,k.jsxs)(`div`,{className:$.findBar,children:[(0,k.jsx)(`input`,{className:$.findInput,value:te,onChange:e=>T(e.target.value),placeholder:`Find...`,autoFocus:!0}),(0,k.jsx)(`input`,{className:$.findInput,value:ne,onChange:e=>re(e.target.value),placeholder:`Replace...`}),(0,k.jsx)(`span`,{className:$.findCount,children:te?((Jt.content||``).match(new RegExp(te.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`gi`))?.length||0)+` found`:``}),(0,k.jsx)(`button`,{className:$.findBtn,onClick:()=>{!te||b===null||x(b.replace(new RegExp(te.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`i`),ne))},children:`Replace`}),(0,k.jsx)(`button`,{className:$.findBtn,onClick:()=>{!te||b===null||x(b.replace(new RegExp(te.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),`gi`),ne))},children:`All`}),(0,k.jsx)(`button`,{className:$.findClose,onClick:()=>ee(!1),children:`×`})]}),Jt._error&&(0,k.jsx)(`div`,{className:$.fileError,children:`⚠ Generazione fallita — chiedi al modello di rigenerare questo file`}),Jt._syntaxError&&!Jt._error&&(0,k.jsxs)(`div`,{className:$.fileSyntaxError,children:[`⚠ Syntax error: `,Jt._syntaxError]}),be&&v!==null?(0,k.jsx)(`pre`,{className:$.streamingPre,ref:e=>{e&&pe.current&&(e.scrollTop=e.scrollHeight)},onScroll:e=>{let t=e.currentTarget;t.scrollHeight-t.scrollTop-t.clientHeight<50?pe.current=!0:(pe.current=!1,me.current&&clearTimeout(me.current),me.current=setTimeout(()=>{pe.current=!0},15e3))},dangerouslySetInnerHTML:{__html:LT(v||``,(Jt.name.split(`.`).pop()||`js`).toLowerCase())+`<span class="`+$.streamingCursor+`">▋</span>`}}):(0,k.jsx)(TT,{value:b===null?Jt.content||``:b,filename:Jt.name,readOnly:b===null,projectName:a,onChange:e=>{x(e),Jt&&C(e=>new Set(e).add(Jt.name))},onSave:e=>{m(t=>t.map((t,n)=>n===h?{...t,content:e}:t)),D(`/api/studio/webcraft/file/write`,{projectName:a,path:Jt.name,content:e}),x(null),C(e=>{let t=new Set(e);return t.delete(Jt.name),t})}})]})}),ae!==null&&p[ae]&&(0,k.jsxs)(`div`,{className:$.codeEditorWrap,children:[(0,k.jsxs)(`div`,{className:$.codeHeader,children:[(0,k.jsx)(`span`,{className:$.codeFileIcon,children:HT(p[ae].name)}),(0,k.jsx)(`span`,{className:$.codeFileName,children:p[ae].name}),(0,k.jsx)(`button`,{className:$.headerIconBtn,onClick:()=>A(null),children:`✕`})]}),(0,k.jsx)(TT,{value:p[ae].content||``,filename:p[ae].name,readOnly:!0})]})]}),ie&&(0,k.jsxs)(`div`,{className:$.terminalPanel,children:[(0,k.jsxs)(`div`,{className:$.terminalHeader,children:[(0,k.jsx)(`span`,{className:$.terminalTitle,children:`Terminal`}),(0,k.jsx)(`button`,{className:$.terminalClose,onClick:()=>O(!1),children:`✕`})]}),(0,k.jsx)(IT,{projectDir:a||void 0})]})]})})]})]})]})}),L&&t!==`projects`&&(0,k.jsxs)(`div`,{className:$.planBanner,children:[(0,k.jsx)(`div`,{className:$.planTitle,children:`📌 Piano proposto — approva per eseguire`}),(0,k.jsx)(`pre`,{className:$.planText,children:L.plan}),(0,k.jsxs)(`div`,{className:$.planActions,children:[(0,k.jsx)(`button`,{className:$.planApprove,onClick:U,children:`✓ Esegui`}),(0,k.jsx)(`button`,{className:$.planReject,onClick:()=>Be(null),children:`✕ Annulla`})]})]}),Ye&&t!==`projects`&&(0,k.jsxs)(`div`,{className:$.grepPanel,children:[(0,k.jsxs)(`div`,{className:$.grepRow,children:[(0,k.jsx)(`input`,{className:$.grepInput,value:Ze,onChange:e=>Qe(e.target.value),onKeyDown:e=>e.key===`Enter`&&Rt(),placeholder:`Cerca nel codice...`}),(0,k.jsx)(`button`,{className:$.grepBtn,onClick:Rt,children:`🔍`}),(0,k.jsx)(`button`,{className:$.grepClose,onClick:()=>Xe(!1),children:`×`})]}),$e.length>0&&(0,k.jsxs)(`div`,{className:$.grepCount,children:[$e.length,` risultati`]}),(0,k.jsx)(`div`,{className:$.grepResults,children:$e.length===0?(0,k.jsx)(`div`,{className:$.grepEmpty,children:`Nessun risultato.`}):$e.map((e,t)=>(0,k.jsxs)(`div`,{className:$.grepMatch,onClick:()=>zt(e.file),children:[(0,k.jsxs)(`span`,{className:$.grepMatchFile,children:[e.file,`:`,e.lineNum]}),(0,k.jsx)(`pre`,{className:$.grepMatchLine,children:e.line})]},t))})]}),tt.length>0&&t!==`projects`&&(0,k.jsxs)(`div`,{className:$.diffPanel,children:[(0,k.jsxs)(`div`,{className:$.diffHeader,children:[(0,k.jsxs)(`span`,{children:[`🔌 Diff — `,tt.length,` file modificati`]}),(0,k.jsx)(`button`,{className:$.diffClose,onClick:()=>nt([]),children:`✕ Chiudi`})]}),tt.map((e,t)=>{let n=e.after.split(`
783
783
  `).length-e.before.split(`
784
- `).length;return(0,k.jsxs)(`details`,{open:!0,className:$.diffFile,children:[(0,k.jsxs)(`summary`,{className:$.diffSummary,children:[(0,k.jsx)(`span`,{className:$.diffArrow,children:`▲`}),(0,k.jsx)(`span`,{className:$.diffFileName,children:e.file}),(0,k.jsxs)(`span`,{className:n>=0?$.diffAdded:$.diffRemoved,children:[n>=0?`+`:``,n,` linee`]})]}),(0,k.jsx)(`div`,{className:$.diffContent,children:(0,k.jsx)(YT,{before:e.before,after:e.after})})]},t)})]}),t!==`projects`&&(0,k.jsxs)(`div`,{className:$.chatPanel,children:[(0,k.jsxs)(`div`,{className:$.chatMessages,ref:vt,children:[Me.length===0&&qt&&(0,k.jsxs)(`div`,{className:$.chatWelcome,children:[`🤖 `,e(`webcraft.doctrine.title`),` — `,(0,k.jsx)(`button`,{className:$.doctrineOpenBtn,onClick:()=>se(!0),children:`📖 Open Guide`})]}),Me.map((e,t)=>(0,k.jsxs)(`div`,{className:e.role===`user`?$.chatUser:e.role===`system`?$.chatSystem:$.chatAgent,children:[e.role===`user`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:$.chatUserBubble,children:e.text}),e.attachments&&e.attachments.length>0&&(0,k.jsx)(`div`,{className:$.chatAttachPreviews,children:e.attachments.map((e,t)=>(0,k.jsxs)(`span`,{className:$.chatAttachBadge,children:[`📎 `,e.name]},t))})]}),e.role===`system`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:$.chatSystemBubble,children:e.text}),e.syntaxErrors?.map((e,t)=>(0,k.jsxs)(`div`,{className:$.chatSyntaxErr,children:[`✕ `,e.file,`: `,e.error]},t))]}),e.role===`agent`&&(0,k.jsxs)(`div`,{className:$.chatAgentCard,children:[(0,k.jsxs)(`div`,{className:$.chatAgentHeader,children:[(0,k.jsx)(`span`,{className:$.chatAgentRobot,children:`🤖`}),(0,k.jsx)(`span`,{className:$.chatAgentLabel,children:`WebCraft Agent`})]}),(0,k.jsx)(`div`,{className:$.chatAgentText,dangerouslySetInnerHTML:{__html:RT(e.text.replace(/<tool>[\s\S]*?<\/tool>/g,``).trim())}}),e.tools&&e.tools.filter(e=>(e.op===`edit`||e.op===`write`)&&e.result===`ok`&&(e.oldSnippet||e.newSnippet)).map((e,t)=>(0,k.jsxs)(`div`,{className:$.diffInline,children:[(0,k.jsxs)(`div`,{className:$.diffInlineHeader,children:[`✏ `,e.path]}),(0,k.jsx)(YT,{before:e.oldSnippet||``,after:e.newSnippet||``,contextLines:5})]},t)),e.tools&&e.tools.length>0&&(0,k.jsx)(`div`,{className:$.chatToolBadges,children:e.tools.map((e,t)=>(0,k.jsxs)(`span`,{className:`${$.toolBadge} ${e.result===`ok`?$.toolBadgeOk:$.toolBadgeErr}`,children:[e.op===`edit`?`✏`:e.op===`write`?`+`:`👁`,` `,e.path]},t))})]})]},t)),Ie&&(0,k.jsxs)(`div`,{className:$.chatAgentCard,children:[(0,k.jsxs)(`div`,{className:$.chatAgentHeader,children:[(0,k.jsx)(`span`,{className:$.chatAgentRobotAnim,children:`🤖`}),(0,k.jsx)(`span`,{className:$.chatAgentLabel,children:`WebCraft Agent`}),(0,k.jsxs)(`span`,{className:$.chatRunningDots,children:[(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot1}`}),(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot2}`}),(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot3}`})]})]}),(0,k.jsx)(`div`,{className:$.chatAgentText,children:(0,k.jsx)(`span`,{className:$.cursor,children:`​`})})]})]}),Re.length>0&&(0,k.jsx)(`div`,{className:$.attachPreviews,children:Re.map((e,t)=>(0,k.jsxs)(`span`,{className:$.attachBadge,children:[`📎 `,e.name,(0,k.jsx)(`button`,{className:$.removeAttachBtn,onClick:()=>ze(e=>e.filter((e,n)=>n!==t)),children:`×`})]},t))}),qt?(0,k.jsxs)(`div`,{className:$.projActiveRow,children:[`📄 `,(0,k.jsx)(`strong`,{className:$.projActiveName,children:a}),` — scrivi per modificare o migliorare il progetto`]}):(0,k.jsxs)(`div`,{className:$.projNameRow,children:[(0,k.jsx)(`span`,{className:$.projNameLabel,children:`Nome progetto:`}),(0,k.jsx)(`input`,{className:$.projNameInput,value:a,onChange:e=>o(e.target.value),placeholder:`MioProgetto`})]}),(0,k.jsxs)(`div`,{className:$.chatInputRow,children:[(0,k.jsxs)(`label`,{className:$.attachLabel,title:`Allega immagine o PDF`,children:[`📎`,(0,k.jsx)(`input`,{ref:yt,type:`file`,multiple:!0,accept:`image/*,.pdf`,style:{display:`none`},onChange:e=>Kt(e.target.files)})]}),(0,k.jsx)(`textarea`,{className:$.chatTextarea,value:Pe,onChange:e=>Fe(e.target.value),placeholder:qt?`Parla con il tuo agente: chiedi correzioni, migliorie, nuove funzionalità...`:`Descrivi il progetto da creare, poi premi Genera...`,disabled:Yt,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),Dt())},rows:4}),(0,k.jsxs)(`div`,{className:$.chatSendCol,children:[(0,k.jsx)(`button`,{className:$.chatSendBtn,onClick:Dt,disabled:Yt,children:be?`⏳`:qt?`▶`:`▶ Genera`}),Yt&&!Se&&(0,k.jsx)(`button`,{className:$.chatStopBtn,onClick:At,children:`⏹ Stop`})]})]})]}),oe&&(0,k.jsx)(`div`,{className:$.modalOverlay,onClick:()=>se(!1),children:(0,k.jsxs)(`div`,{className:$.modal,onClick:e=>e.stopPropagation(),style:{width:720,maxHeight:`90vh`},children:[(0,k.jsxs)(`div`,{className:$.modalHeader,children:[(0,k.jsxs)(`span`,{className:$.modalTitle,children:[`📖 `,e(`webcraft.doctrine.title`)]}),(0,k.jsx)(`span`,{className:$.doctrineSubtitle,children:e(`webcraft.doctrine.subtitle`)}),(0,k.jsx)(`button`,{className:$.modalClose,onClick:()=>se(!1),children:`✕`})]}),(0,k.jsx)(`div`,{className:$.modalBody,style:{gap:0},children:[`phase1`,`phase2`,`phase3`,`phase4`,`phase5`,`tools`,`golden`].map(t=>(0,k.jsxs)(`div`,{className:$.doctrineSection,children:[(0,k.jsx)(`div`,{className:$.doctrineSectionTitle,children:e(`webcraft.doctrine.${t}.title`)}),(0,k.jsx)(`div`,{className:$.doctrineSectionBody,children:e(`webcraft.doctrine.${t}.desc`).split(`
784
+ `).length;return(0,k.jsxs)(`details`,{open:!0,className:$.diffFile,children:[(0,k.jsxs)(`summary`,{className:$.diffSummary,children:[(0,k.jsx)(`span`,{className:$.diffArrow,children:`▲`}),(0,k.jsx)(`span`,{className:$.diffFileName,children:e.file}),(0,k.jsxs)(`span`,{className:n>=0?$.diffAdded:$.diffRemoved,children:[n>=0?`+`:``,n,` linee`]})]}),(0,k.jsx)(`div`,{className:$.diffContent,children:(0,k.jsx)(YT,{before:e.before,after:e.after})})]},t)})]}),t!==`projects`&&(0,k.jsxs)(`div`,{className:$.chatPanel,children:[(0,k.jsxs)(`div`,{className:$.chatMessages,ref:vt,children:[Me.length===0&&qt&&(0,k.jsxs)(`div`,{className:$.chatWelcome,children:[`🤖 `,e(`webcraft.doctrine.title`),` — `,(0,k.jsx)(`button`,{className:$.doctrineOpenBtn,onClick:()=>se(!0),children:`📖 Open Guide`})]}),Me.map((e,t)=>(0,k.jsxs)(`div`,{className:e.role===`user`?$.chatUser:e.role===`system`?$.chatSystem:$.chatAgent,children:[e.role===`user`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:$.chatUserBubble,children:e.text}),e.attachments&&e.attachments.length>0&&(0,k.jsx)(`div`,{className:$.chatAttachPreviews,children:e.attachments.map((e,t)=>(0,k.jsxs)(`span`,{className:$.chatAttachBadge,children:[`📎 `,e.name]},t))})]}),e.role===`system`&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:$.chatSystemBubble,children:e.text}),e.syntaxErrors?.map((e,t)=>(0,k.jsxs)(`div`,{className:$.chatSyntaxErr,children:[`✕ `,e.file,`: `,e.error]},t))]}),e.role===`agent`&&(0,k.jsxs)(`div`,{className:$.chatAgentCard,children:[(0,k.jsxs)(`div`,{className:$.chatAgentHeader,children:[(0,k.jsx)(`span`,{className:$.chatAgentRobot,children:`🤖`}),(0,k.jsx)(`span`,{className:$.chatAgentLabel,children:`WebCraft Agent`})]}),(0,k.jsx)(`div`,{className:$.chatAgentText,dangerouslySetInnerHTML:{__html:RT(e.text.replace(/<tool>[\s\S]*?<\/tool>/g,``).trim())}}),e.tools&&e.tools.filter(e=>(e.op===`edit`||e.op===`write`)&&e.result===`ok`&&(e.oldSnippet||e.newSnippet)).map((e,t)=>(0,k.jsxs)(`div`,{className:$.diffInline,children:[(0,k.jsxs)(`div`,{className:$.diffInlineHeader,children:[`✏ `,e.path]}),(0,k.jsx)(YT,{before:e.oldSnippet||``,after:e.newSnippet||``,contextLines:5})]},t)),e.tools&&e.tools.length>0&&(0,k.jsx)(`div`,{className:$.chatToolBadges,children:e.tools.map((e,t)=>(0,k.jsxs)(`span`,{className:`${$.toolBadge} ${e.result===`ok`?$.toolBadgeOk:$.toolBadgeErr}`,children:[e.op===`edit`?`✏`:e.op===`write`?`+`:`👁`,` `,e.path]},t))})]})]},t)),Ie&&(()=>{let e=Me[Me.length-1]?.tools??[],t=e[e.length-1];return(0,k.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8,padding:`6px 12px`,background:`rgba(99,102,241,0.08)`,borderRadius:8,fontSize:11,color:`#818cf8`,margin:`4px 0`},children:[(0,k.jsx)(`span`,{className:$.chatAgentRobotAnim,children:`🤖`}),(0,k.jsx)(`span`,{style:{fontWeight:600},children:`Working`}),(0,k.jsxs)(`span`,{className:$.chatRunningDots,children:[(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot1}`}),(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot2}`}),(0,k.jsx)(`span`,{className:`${$.dot} ${$.dot3}`})]}),t&&(0,k.jsxs)(`span`,{style:{color:`var(--dim)`,marginLeft:8},children:[t.op===`read`?`📖`:t.op===`edit`?`✏️`:t.op===`write`?`📝`:t.op===`search`?`🔍`:t.op===`lint`?`🔬`:t.op===`check`?`✓`:t.op===`run`?`▶`:t.op===`sandbox`?`🌐`:`🔧`,` `,t.path||t.op,` → `,t.result===`ok`?`✅`:t.result?.startsWith(`error`)?`❌`:t.result?.slice(0,30)]})]})})()]}),Re.length>0&&(0,k.jsx)(`div`,{className:$.attachPreviews,children:Re.map((e,t)=>(0,k.jsxs)(`span`,{className:$.attachBadge,children:[`📎 `,e.name,(0,k.jsx)(`button`,{className:$.removeAttachBtn,onClick:()=>ze(e=>e.filter((e,n)=>n!==t)),children:`×`})]},t))}),qt?(0,k.jsxs)(`div`,{className:$.projActiveRow,children:[`📄 `,(0,k.jsx)(`strong`,{className:$.projActiveName,children:a}),` — scrivi per modificare o migliorare il progetto`]}):(0,k.jsxs)(`div`,{className:$.projNameRow,children:[(0,k.jsx)(`span`,{className:$.projNameLabel,children:`Nome progetto:`}),(0,k.jsx)(`input`,{className:$.projNameInput,value:a,onChange:e=>o(e.target.value),placeholder:`MioProgetto`})]}),(0,k.jsxs)(`div`,{className:$.chatInputRow,children:[(0,k.jsxs)(`label`,{className:$.attachLabel,title:`Allega immagine o PDF`,children:[`📎`,(0,k.jsx)(`input`,{ref:yt,type:`file`,multiple:!0,accept:`image/*,.pdf`,style:{display:`none`},onChange:e=>Kt(e.target.files)})]}),(0,k.jsx)(`textarea`,{className:$.chatTextarea,value:Pe,onChange:e=>Fe(e.target.value),placeholder:qt?`Parla con il tuo agente: chiedi correzioni, migliorie, nuove funzionalità...`:`Descrivi il progetto da creare, poi premi Genera...`,disabled:Yt,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),Dt())},rows:4}),(0,k.jsxs)(`div`,{className:$.chatSendCol,children:[(0,k.jsx)(`button`,{className:$.chatSendBtn,onClick:Dt,disabled:Yt,children:be?`⏳`:qt?`▶`:`▶ Genera`}),Yt&&!Se&&(0,k.jsx)(`button`,{className:$.chatStopBtn,onClick:At,children:`⏹ Stop`})]})]})]}),oe&&(0,k.jsx)(`div`,{className:$.modalOverlay,onClick:()=>se(!1),children:(0,k.jsxs)(`div`,{className:$.modal,onClick:e=>e.stopPropagation(),style:{width:720,maxHeight:`90vh`},children:[(0,k.jsxs)(`div`,{className:$.modalHeader,children:[(0,k.jsxs)(`span`,{className:$.modalTitle,children:[`📖 `,e(`webcraft.doctrine.title`)]}),(0,k.jsx)(`span`,{className:$.doctrineSubtitle,children:e(`webcraft.doctrine.subtitle`)}),(0,k.jsx)(`button`,{className:$.modalClose,onClick:()=>se(!1),children:`✕`})]}),(0,k.jsx)(`div`,{className:$.modalBody,style:{gap:0},children:[`phase1`,`phase2`,`phase3`,`phase4`,`phase5`,`tools`,`golden`].map(t=>(0,k.jsxs)(`div`,{className:$.doctrineSection,children:[(0,k.jsx)(`div`,{className:$.doctrineSectionTitle,children:e(`webcraft.doctrine.${t}.title`)}),(0,k.jsx)(`div`,{className:$.doctrineSectionBody,children:e(`webcraft.doctrine.${t}.desc`).split(`
785
785
  `).map((e,t)=>(0,k.jsx)(`p`,{className:e.startsWith(`•`)||e.startsWith(`1.`)||e.startsWith(`2.`)||e.startsWith(`3.`)||e.startsWith(`4.`)||e.startsWith(`5.`)||e.startsWith(`6.`)?$.doctrineBullet:``,children:e},t))})]},t))}),(0,k.jsx)(`div`,{className:$.modalFooter,children:(0,k.jsx)(`button`,{className:$.modalSaveBtn,onClick:()=>se(!1),style:{padding:`10px 28px`,fontSize:14},children:e(`webcraft.doctrine.close`)})})]})}),Ge&&(0,k.jsx)(XT,{modal:Ge,skills:Ve,projectName:a,onClose:()=>Ke(null),onSave:(e,t,n)=>H(Ge,e,t,n)})]})}function KT(e,t){let n=e.length,r=t.length;if(n===0&&r===0)return[];if(n===r&&e.every((e,n)=>e===t[n]))return e.map((e,t)=>({type:`same`,text:e,oldLine:t+1,newLine:t+1}));if(n+r>8e3)return qT(e,t);let i=n+r,a=2*i+1,o=new Int32Array(a).fill(-1);new Int32Array(a).fill(-1);let s=i;o[s+1]=0;let c=[];outer:for(let l=0;l<=i;l++){let i=new Int32Array(a);i.set(o),c.push(i);for(let i=-l;i<=l;i+=2){let a;a=i===-l||i!==l&&o[s+i-1]<o[s+i+1]?o[s+i+1]:o[s+i-1]+1;let c=a-i;for(;a<n&&c<r&&e[a]===t[c];)a++,c++;if(o[s+i]=a,a>=n&&c>=r)break outer}}let l=[],u=n,d=r;for(let n=c.length-1;n>0;n--){let r=c[n-1],i=u-d,a;a=i===-n||i!==n&&r[s+i-1]<r[s+i+1]?i+1:i-1;let o=r[s+a],f=o-a;for(;u>o&&d>f;)u--,d--,l.push({type:`same`,text:e[u],oldLine:u+1,newLine:d+1});u>o?(u--,l.push({type:`rem`,text:e[u],oldLine:u+1})):d>f&&(d--,l.push({type:`add`,text:t[d],newLine:d+1}))}for(;u>0&&d>0;)u--,d--,l.push({type:`same`,text:e[u],oldLine:u+1,newLine:d+1});return l.reverse(),l}function qT(e,t){let n=[],r=0,i=0;for(;(r<e.length||i<t.length)&&(r>=e.length?(n.push({type:`add`,text:t[i],newLine:i+1}),i++):i>=t.length?(n.push({type:`rem`,text:e[r],oldLine:r+1}),r++):e[r]===t[i]?(n.push({type:`same`,text:e[r],oldLine:r+1,newLine:i+1}),r++,i++):(n.push({type:`rem`,text:e[r],oldLine:r+1}),n.push({type:`add`,text:t[i],newLine:i+1}),r++,i++),!(n.length>4e3)););return n}function JT(e,t){let n=e.split(/(\s+)/),r=t.split(/(\s+)/),i=n.length,a=r.length;if(i+a>400)return{old:(0,k.jsx)(k.Fragment,{children:e}),new:(0,k.jsx)(k.Fragment,{children:t})};let o=Array.from({length:i+1},()=>Array(a+1).fill(0));for(let e=1;e<=i;e++)for(let t=1;t<=a;t++)o[e][t]=n[e-1]===r[t-1]?o[e-1][t-1]+1:Math.max(o[e-1][t],o[e][t-1]);let s=[],c=[],l=i,u=a,d=[],f=[];for(;l>0||u>0;)l>0&&u>0&&n[l-1]===r[u-1]?(d.push({text:n[l-1],changed:!1}),f.push({text:r[u-1],changed:!1}),l--,u--):u>0&&(l===0||o[l][u-1]>=o[l-1][u])?(f.push({text:r[u-1],changed:!0}),u--):(d.push({text:n[l-1],changed:!0}),l--);return d.reverse().forEach(e=>s.push(e)),f.reverse().forEach(e=>c.push(e)),{old:(0,k.jsx)(k.Fragment,{children:s.map((e,t)=>e.changed?(0,k.jsx)(`span`,{style:{background:`rgba(248,113,113,0.3)`,borderRadius:2},children:e.text},t):(0,k.jsx)(`span`,{children:e.text},t))}),new:(0,k.jsx)(k.Fragment,{children:c.map((e,t)=>e.changed?(0,k.jsx)(`span`,{style:{background:`rgba(74,222,128,0.3)`,borderRadius:2},children:e.text},t):(0,k.jsx)(`span`,{children:e.text},t))})}}function YT({before:e,after:t,contextLines:n=3}){let r=KT(e.split(`
786
786
  `),t.split(`
787
787
  `)),i=new Set;r.forEach((e,t)=>{e.type!==`same`&&i.add(t)});let a=new Set;if(i.forEach(e=>{for(let t=Math.max(0,e-n);t<=Math.min(r.length-1,e+n);t++)a.add(t)}),i.size===0)for(let e=0;e<Math.min(5,r.length);e++)a.add(e);let o=new Map;for(let e=0;e<r.length-1;e++)r[e].type===`rem`&&r[e+1].type===`add`&&o.set(e,JT(r[e].text,r[e+1].text));let s=[],c=-1;for(let e=0;e<r.length;e++){if(!a.has(e))continue;if(c>=0&&e-c>1){let t=e-c-1;s.push((0,k.jsxs)(`div`,{style:{padding:`2px 8px`,background:`rgba(99,102,241,0.08)`,color:`#6366f1`,fontSize:9,textAlign:`center`,borderTop:`1px solid rgba(99,102,241,0.15)`,borderBottom:`1px solid rgba(99,102,241,0.15)`,userSelect:`none`},children:[`@@ `,t,` righe nascoste @@`]},`fold-${e}`))}c=e;let t=r[e],n=t.type===`add`?`rgba(74,222,128,0.08)`:t.type===`rem`?`rgba(248,113,113,0.08)`:`transparent`,i=t.type===`add`?`3px solid #4ade80`:t.type===`rem`?`3px solid #f87171`:`3px solid transparent`,l=t.type===`add`?`#4ade80`:t.type===`rem`?`#f87171`:`var(--dim)`,u=t.type===`add`?`+`:t.type===`rem`?`-`:` `,d=t.text,f=o.get(e);f&&t.type===`rem`&&(d=f.old);let p=o.get(e-1);p&&t.type===`add`&&(d=p.new),s.push((0,k.jsxs)(`div`,{style:{display:`flex`,alignItems:`stretch`,background:n,borderLeft:i,fontFamily:`var(--mono)`,fontSize:11,lineHeight:`18px`},children:[(0,k.jsx)(`span`,{style:{width:36,textAlign:`right`,padding:`0 4px`,color:`rgba(255,255,255,0.2)`,fontSize:10,flexShrink:0,userSelect:`none`},children:t.oldLine??``}),(0,k.jsx)(`span`,{style:{width:36,textAlign:`right`,padding:`0 4px`,color:`rgba(255,255,255,0.2)`,fontSize:10,flexShrink:0,userSelect:`none`},children:t.newLine??``}),(0,k.jsx)(`span`,{style:{width:14,textAlign:`center`,color:l,fontWeight:700,flexShrink:0,userSelect:`none`},children:u}),(0,k.jsx)(`span`,{style:{flex:1,padding:`0 4px`,color:l,whiteSpace:`pre-wrap`,wordBreak:`break-all`},children:d})]},e))}return(0,k.jsx)(`div`,{style:{overflow:`auto`,maxHeight:400},children:s})}function XT({modal:e,skills:t,projectName:n,onClose:r,onSave:i}){let[a,o]=(0,_.useState)(e.name),[s,c]=(0,_.useState)(e.content),[l,u]=(0,_.useState)(e.type),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(!1),h=l===`skill`?6e3:4e3,g=s.length>h;async function v(){if(!d.trim())return;m(!0);let e={skill:`Sei un esperto di sviluppo web fullstack. Genera un file Markdown "skill" per il WebCraft Agent. Deve contenere istruzioni, pattern di codice, best practice e snippet pronti all uso come contesto persistente. Scrivi SOLO il contenuto Markdown, niente altro.`,memory:`Sei un assistente tecnico. Genera un file Markdown "memory" per il WebCraft Agent. Deve riassumere decisioni architetturali, preferenze dello sviluppatore e contesto generale del progetto. Scrivi SOLO il Markdown.`,provider:`Sei un esperto di prompt engineering. Genera un file Markdown con istruzioni specifiche per calibrare il comportamento del modello AI. Scrivi SOLO il Markdown.`},t=await D(`/api/studio/webcraft`,{system:e[l]??e.skill,user:`Progetto: ${n}\n\n${d}`,max_tokens:2048});t?.text&&(c(t.text),a||o(l===`memory`?`memory.md`:l===`provider`?`liara.md`:d.toLowerCase().replace(/[^a-z0-9]+/g,`-`).slice(0,30)+`.md`)),m(!1)}function y(){if(!a.trim()){alert(`Inserisci un nome per il file.`);return}let n=a.endsWith(`.md`)?a:a+`.md`;if((l===`memory`||l===`provider`)&&e.mode===`new`&&t.findIndex(e=>e.type===l)>=0){alert(`Esiste già un file di tipo "${l}". Modificalo direttamente.`);return}i(n,s,l)}return(0,k.jsx)(`div`,{className:$.modalOverlay,onClick:e=>{e.target===e.currentTarget&&r()},children:(0,k.jsxs)(`div`,{className:$.modal,children:[(0,k.jsxs)(`div`,{className:$.modalHeader,children:[(0,k.jsxs)(`span`,{className:$.modalTitle,children:[WT(l),` `,e.mode===`new`?`Nuovo file di contesto`:`Modifica ${e.name}`]}),(0,k.jsx)(`button`,{className:$.modalClose,onClick:r,children:`×`})]}),(0,k.jsx)(`div`,{className:$.modalBody,children:e.mode===`view`?(0,k.jsx)(`pre`,{className:$.logView,children:s}):(0,k.jsxs)(k.Fragment,{children:[e.mode===`new`&&(0,k.jsxs)(`div`,{className:$.modalRow,children:[(0,k.jsxs)(`div`,{className:$.modalField,children:[(0,k.jsx)(`div`,{className:$.modalLabel,children:`TIPO`}),(0,k.jsx)(`select`,{value:l,onChange:e=>{let t=e.target.value;u(t),t===`memory`?o(`memory.md`):t===`provider`&&o(`liara.md`)},className:$.modalSelect,children:[`skill`,`memory`,`provider`].map(e=>{let n=(e===`memory`||e===`provider`)&&t.some(t=>t.type===e);return(0,k.jsxs)(`option`,{value:e,disabled:n,children:[e,n?` (esiste già)`:``]},e)})})]}),(0,k.jsxs)(`div`,{className:$.modalField,style:{flex:2},children:[(0,k.jsx)(`div`,{className:$.modalLabel,children:`NOME FILE`}),(0,k.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),placeholder:l===`memory`?`memory.md`:l===`provider`?`liara.md`:`nome-skill.md`,className:$.modalInput})]})]}),(0,k.jsxs)(`div`,{className:$.modalHint,children:[`💡 `,l===`skill`?`Istruzioni tecniche, snippet, pattern di codice specifici. Max ~6000 caratteri.`:l===`memory`?`Note persistenti sul progetto: decisioni architetturali, preferenze. Solo UN file. Max ~4000 caratteri.`:`Istruzioni specifiche per il modello AI (tono, formato, vincoli). Solo UN file. Max ~4000 caratteri.`]}),(0,k.jsxs)(`div`,{className:$.modalAiBox,children:[(0,k.jsx)(`div`,{className:$.modalLabel,children:`🤖 GENERA CON AI`}),(0,k.jsxs)(`div`,{className:$.modalAiRow,children:[(0,k.jsx)(`textarea`,{value:d,onChange:e=>f(e.target.value),rows:2,placeholder:`Descrivi cosa deve contenere questo file...`,className:$.modalAiDesc}),(0,k.jsx)(`button`,{onClick:v,disabled:p,className:$.modalAiBtn,children:p?`⏳ ...`:`▶ Genera`})]})]}),(0,k.jsxs)(`div`,{children:[(0,k.jsxs)(`div`,{className:$.modalLabelRow,children:[(0,k.jsx)(`span`,{children:`CONTENUTO (markdown)`}),(0,k.jsxs)(`span`,{style:{color:g?`#e05050`:`var(--dim)`},children:[s.length,` car.`,g?` ⚠ Troppo lungo`:``]})]}),(0,k.jsx)(`textarea`,{value:s,onChange:e=>c(e.target.value),rows:14,placeholder:`# Titolo
@@ -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-wcl8Kj42.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-wpLo6Nu6.js"></script>
12
12
  <link rel="stylesheet" crossorigin href="/assets/index-CIozt-VX.css">
13
13
  </head>
14
14
  <body>