zugzbot 1.0.11 → 1.0.13

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.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="46" fill="none" viewBox="0 0 48 46"><path fill="#863bff" d="M25.946 44.938c-.664.845-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.287c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.497 0-3.578-1.842-3.578H1.237c-.92 0-1.456-1.04-.92-1.788L10.013.474c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.579 1.842 3.579h11.377c.943 0 1.473 1.088.89 1.83L25.947 44.94z" style="fill:#863bff;fill:color(display-p3 .5252 .23 1);fill-opacity:1"/><mask id="a" width="48" height="46" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#000" d="M25.842 44.938c-.664.844-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.183c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.498 0-3.579-1.842-3.579H1.133c-.92 0-1.456-1.04-.92-1.787L9.91.473c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.578 1.842 3.578h11.377c.943 0 1.473 1.088.89 1.832L25.843 44.94z" style="fill:#000;fill-opacity:1"/></mask><g mask="url(#a)"><g filter="url(#b)"><ellipse cx="5.508" cy="14.704" fill="#ede6ff" rx="5.508" ry="14.704" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -4.47 31.516)"/></g><g filter="url(#c)"><ellipse cx="10.399" cy="29.851" fill="#ede6ff" rx="10.399" ry="29.851" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -39.328 7.883)"/></g><g filter="url(#d)"><ellipse cx="5.508" cy="30.487" fill="#7e14ff" rx="5.508" ry="30.487" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -25.913 -14.639)scale(1 -1)"/></g><g filter="url(#e)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -32.644 -3.334)scale(1 -1)"/></g><g filter="url(#f)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -34.34 30.47)"/></g><g filter="url(#g)"><ellipse cx="14.072" cy="22.078" fill="#ede6ff" rx="14.072" ry="22.078" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="rotate(93.35 24.506 48.493)scale(-1 1)"/></g><g filter="url(#h)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#i)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#j)"><ellipse cx=".387" cy="8.972" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(39.51 .387 8.972)"/></g><g filter="url(#k)"><ellipse cx="47.523" cy="-6.092" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 47.523 -6.092)"/></g><g filter="url(#l)"><ellipse cx="41.412" cy="6.333" fill="#47bfff" rx="5.971" ry="9.665" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 41.412 6.333)"/></g><g filter="url(#m)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#n)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#o)"><ellipse cx="35.651" cy="29.907" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 35.651 29.907)"/></g><g filter="url(#p)"><ellipse cx="38.418" cy="32.4" fill="#47bfff" rx="5.971" ry="15.297" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 38.418 32.4)"/></g></g><defs><filter id="b" width="60.045" height="41.654" x="-19.77" y="16.149" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="c" width="90.34" height="51.437" x="-54.613" y="-7.533" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="d" width="79.355" height="29.4" x="-49.64" y="2.03" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="e" width="79.579" height="29.4" x="-45.045" y="20.029" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="f" width="79.579" height="29.4" x="-43.513" y="21.178" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="g" width="74.749" height="58.852" x="15.756" y="-17.901" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="h" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="i" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="j" width="56.045" height="63.649" x="-27.636" y="-22.853" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="k" width="54.814" height="64.646" x="20.116" y="-38.415" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="l" width="33.541" height="35.313" x="24.641" y="-11.323" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="m" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="n" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="o" width="54.814" height="64.646" x="8.244" y="-2.416" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="p" width="39.409" height="43.623" x="18.713" y="10.588" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter></defs></svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg">
2
+ <symbol id="bluesky-icon" viewBox="0 0 16 17">
3
+ <g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
4
+ <defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
5
+ </symbol>
6
+ <symbol id="discord-icon" viewBox="0 0 20 19">
7
+ <path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
8
+ </symbol>
9
+ <symbol id="documentation-icon" viewBox="0 0 21 20">
10
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
11
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
12
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
13
+ </symbol>
14
+ <symbol id="github-icon" viewBox="0 0 19 19">
15
+ <path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
16
+ </symbol>
17
+ <symbol id="social-icon" viewBox="0 0 20 20">
18
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
19
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
20
+ </symbol>
21
+ <symbol id="x-icon" viewBox="0 0 19 19">
22
+ <path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
23
+ </symbol>
24
+ </svg>
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>client</title>
8
+ <script type="module" crossorigin src="/assets/index-DXxAlmSX.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CcbbJtSz.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
@@ -567,6 +567,147 @@ export default function App() {
567
567
  setExpandedProjects(prev => ({ ...prev, [projectId]: !prev[projectId] }))
568
568
  }
569
569
 
570
+ // Activa un proyecto levantando opencode serve en su directorio en segundo plano
571
+ const handleActivateProject = async (projectId: string) => {
572
+ const project = projects.find(p => p.id === projectId)
573
+ if (!project) return
574
+
575
+ setIsProcessing(true)
576
+ setErrorMsg('Activando entorno de proyecto en segundo plano...')
577
+ try {
578
+ const res = await fetch('/api-custom/activate-project', {
579
+ method: 'POST',
580
+ headers: { 'Content-Type': 'application/json' },
581
+ body: JSON.stringify({ path: project.path })
582
+ })
583
+ if (res.ok) {
584
+ setActiveProjectId(projectId)
585
+
586
+ // Limpiar estados de sesión de la instancia anterior
587
+ setSessions([])
588
+ setCurrentSessionId('')
589
+ setCurrentSession(null)
590
+ setMessages([])
591
+
592
+ // Forzar recarga de sesiones del nuevo entorno
593
+ await fetchSessions()
594
+ setErrorMsg('')
595
+ } else {
596
+ const errData = await res.json().catch(() => ({}))
597
+ setErrorMsg(errData.error || 'Error al activar el proyecto')
598
+ }
599
+ } catch {
600
+ setErrorMsg('No se pudo conectar con el Daemon para activar el proyecto')
601
+ } finally {
602
+ setIsProcessing(false)
603
+ }
604
+ }
605
+
606
+ // Crea e inicia de forma inmediata una sesión dentro de un proyecto específico de un solo clic
607
+ const handleCreateSessionInProject = async (projectId: string) => {
608
+ const project = projects.find(p => p.id === projectId)
609
+ if (!project) return
610
+
611
+ // 1. Si el proyecto no es el activo, activarlo primero en segundo plano de forma transparente
612
+ if (activeProjectId !== projectId) {
613
+ setIsProcessing(true)
614
+ setErrorMsg(`Activando entorno de "${project.name}"...`)
615
+ try {
616
+ const res = await fetch('/api-custom/activate-project', {
617
+ method: 'POST',
618
+ headers: { 'Content-Type': 'application/json' },
619
+ body: JSON.stringify({ path: project.path })
620
+ })
621
+ if (res.ok) {
622
+ setActiveProjectId(projectId)
623
+ setSessions([])
624
+ setCurrentSessionId('')
625
+ setCurrentSession(null)
626
+ setMessages([])
627
+ setErrorMsg('')
628
+ } else {
629
+ alert(`No se pudo activar el proyecto: ${project.name}`)
630
+ setIsProcessing(false)
631
+ return
632
+ }
633
+ } catch {
634
+ alert(`Error al conectar al Daemon para activar el proyecto: ${project.name}`)
635
+ setIsProcessing(false)
636
+ return
637
+ }
638
+ }
639
+
640
+ // 2. Solicitar el título de la sesión de forma sencilla
641
+ const title = prompt(`Introduce el título de la nueva sesión para "${project.name}":`, `Sesión ${new Date().toLocaleDateString()}`)
642
+ if (!title || !title.trim()) return
643
+
644
+ setIsProcessing(true)
645
+ setErrorMsg('Iniciando sesión...')
646
+ try {
647
+ const res = await fetch('/api/session', {
648
+ method: 'POST',
649
+ headers: { 'Content-Type': 'application/json' },
650
+ body: JSON.stringify({ title: title.trim() })
651
+ })
652
+ if (res.ok) {
653
+ const newSess = await res.json()
654
+ setSessions(prev => [newSess, ...prev])
655
+ setCurrentSessionId(newSess.id)
656
+ setCurrentSession(newSess)
657
+ setMessages([])
658
+
659
+ // Guardar mapeo sesión -> proyecto
660
+ setSessionMappings(prev => ({
661
+ ...prev,
662
+ [newSess.id]: projectId
663
+ }))
664
+
665
+ // Redirigir a la vista de chat
666
+ navigateTo('/')
667
+ } else {
668
+ alert('Error al crear la sesión en Opencode')
669
+ }
670
+ } catch {
671
+ alert('Error de conexión al crear sesión')
672
+ } finally {
673
+ setIsProcessing(false)
674
+ setErrorMsg('')
675
+ }
676
+ }
677
+
678
+ // Elimina de forma permanente una sesión y sus mensajes en la API de Opencode
679
+ const handleDeleteSession = async (sessionId: string, e: React.MouseEvent) => {
680
+ e.stopPropagation()
681
+
682
+ if (!confirm('¿Estás seguro de que quieres eliminar esta sesión y todos sus mensajes permanentemente?')) {
683
+ return
684
+ }
685
+
686
+ try {
687
+ const res = await fetch(`/api/session/${sessionId}`, {
688
+ method: 'DELETE'
689
+ })
690
+ if (res.ok) {
691
+ setSessions(prev => prev.filter(s => s.id !== sessionId))
692
+ setSessionMappings(prev => {
693
+ const copy = { ...prev }
694
+ delete copy[sessionId]
695
+ return copy
696
+ })
697
+
698
+ if (currentSessionId === sessionId) {
699
+ setCurrentSessionId('')
700
+ setCurrentSession(null)
701
+ setMessages([])
702
+ }
703
+ } else {
704
+ alert('No se pudo eliminar la sesión de Opencode')
705
+ }
706
+ } catch {
707
+ alert('Error de red al eliminar la sesión')
708
+ }
709
+ }
710
+
570
711
  // Handler para el resize de la barra lateral
571
712
  const handleMouseDown = (e: React.MouseEvent) => {
572
713
  e.preventDefault()
@@ -980,9 +1121,16 @@ export default function App() {
980
1121
  </button>
981
1122
 
982
1123
  <div className="flex items-center gap-1 shrink-0 ml-1">
1124
+ <button
1125
+ onClick={() => handleCreateSessionInProject(project.id)}
1126
+ className="p-1 hover:bg-[#27272a] text-emerald-500 hover:text-emerald-400 rounded transition cursor-pointer"
1127
+ title="Crear Sesión en este proyecto"
1128
+ >
1129
+ <Plus size={10} strokeWidth={3} />
1130
+ </button>
983
1131
  {!isProjectActive && (
984
1132
  <button
985
- onClick={() => setActiveProjectId(project.id)}
1133
+ onClick={() => handleActivateProject(project.id)}
986
1134
  className="p-1 hover:bg-[#27272a] text-[#71717a] hover:text-white rounded transition cursor-pointer"
987
1135
  title="Activar Proyecto"
988
1136
  >
@@ -1017,26 +1165,37 @@ export default function App() {
1017
1165
  return (
1018
1166
  <div key={root.id} className="space-y-1">
1019
1167
  {/* Sesión Principal */}
1020
- <button
1021
- onClick={() => {
1022
- setCurrentSessionId(root.id)
1023
- setErrorMsg('')
1024
- navigateTo('/')
1025
- }}
1026
- className={`w-full text-left p-2.5 rounded-lg flex flex-col gap-0.5 transition duration-200 cursor-pointer ${
1027
- isRootActive
1028
- ? 'bg-[#1c1c1f] border border-[#2e2e33] text-white shadow-sm'
1029
- : 'hover:bg-[#121215] text-[#a1a1aa] hover:text-white'
1030
- }`}
1031
- >
1032
- <span className="font-semibold truncate text-[11px]">
1033
- 💬 {root.title || `Sesión: ${root.id.substring(0, 8)}`}
1034
- </span>
1035
- <div className="flex items-center justify-between text-[9px] text-[#52525b]">
1036
- <span>{root.agent || 'sdd-orchestrator'}</span>
1037
- <span>{formatModelName(root.model)}</span>
1038
- </div>
1039
- </button>
1168
+ <div className={`w-full group/sess flex items-center justify-between rounded-lg p-1.5 transition duration-200 ${
1169
+ isRootActive
1170
+ ? 'bg-[#1c1c1f] border border-[#2e2e33] text-white shadow-sm'
1171
+ : 'hover:bg-[#121215] text-[#a1a1aa] hover:text-white'
1172
+ }`}>
1173
+ <button
1174
+ onClick={() => {
1175
+ setCurrentSessionId(root.id)
1176
+ setErrorMsg('')
1177
+ navigateTo('/')
1178
+ }}
1179
+ className="flex-1 text-left cursor-pointer outline-none min-w-0"
1180
+ >
1181
+ <span className="font-semibold truncate text-[11px] block">
1182
+ 💬 {root.title || `Sesión: ${root.id.substring(0, 8)}`}
1183
+ </span>
1184
+ <div className="flex items-center justify-between text-[9px] text-[#52525b] mt-0.5">
1185
+ <span>{root.agent || 'sdd-orchestrator'}</span>
1186
+ <span>{formatModelName(root.model)}</span>
1187
+ </div>
1188
+ </button>
1189
+
1190
+ {/* Botón de eliminar sesión */}
1191
+ <button
1192
+ onClick={(e) => handleDeleteSession(root.id, e)}
1193
+ className="opacity-0 group-hover/sess:opacity-100 p-1 hover:bg-red-950/40 text-[#71717a] hover:text-red-400 rounded transition cursor-pointer shrink-0 ml-1"
1194
+ title="Eliminar Sesión"
1195
+ >
1196
+ <Square size={10} />
1197
+ </button>
1198
+ </div>
1040
1199
 
1041
1200
  {/* Subagentes hijas */}
1042
1201
  {hasSubagents && (
@@ -192,6 +192,55 @@ const startServer = () => {
192
192
  return
193
193
  }
194
194
 
195
+ // 3c. Endpoint: Activar un proyecto levantando opencode serve en su directorio
196
+ if (req.url === '/api-custom/activate-project' && req.method === 'POST') {
197
+ let body = ''
198
+ req.on('data', chunk => body += chunk)
199
+ req.on('end', () => {
200
+ try {
201
+ const parsed = JSON.parse(body)
202
+ const targetPath = parsed.path
203
+ if (targetPath && path.isAbsolute(targetPath)) {
204
+ // 1. Matar cualquier proceso escuchando en el puerto 4096 (el puerto por defecto)
205
+ exec('lsof -t -i :4096', (err, stdout) => {
206
+ if (stdout) {
207
+ const pids = stdout.split('\n').filter(Boolean)
208
+ for (const pid of pids) {
209
+ try {
210
+ process.kill(parseInt(pid, 10), 'SIGKILL')
211
+ } catch (e) {
212
+ // ignore
213
+ }
214
+ }
215
+ }
216
+
217
+ // 2. Levantar opencode serve con cwd set al directorio del proyecto
218
+ console.log(`\x1b[35m%s\x1b[0m`, `🚀 Levantando opencode serve en: ${targetPath}`)
219
+ const opencodeProcess = spawn('opencode', ['serve', '--port', '4096'], {
220
+ cwd: targetPath,
221
+ detached: true,
222
+ stdio: 'ignore'
223
+ })
224
+ opencodeProcess.unref()
225
+
226
+ // Esperar a que el servidor esté listo
227
+ setTimeout(() => {
228
+ res.writeHead(200, { 'Content-Type': 'application/json' })
229
+ res.end(JSON.stringify({ success: true, message: `Proyecto activo en ${targetPath}` }))
230
+ }, 2000)
231
+ })
232
+ } else {
233
+ res.writeHead(400, { 'Content-Type': 'application/json' })
234
+ res.end(JSON.stringify({ error: 'Ruta absoluta inválida o ausente' }))
235
+ }
236
+ } catch (e) {
237
+ res.writeHead(500, { 'Content-Type': 'application/json' })
238
+ res.end(JSON.stringify({ error: 'Error al activar el proyecto', detail: e.message }))
239
+ }
240
+ })
241
+ return
242
+ }
243
+
195
244
  // 4. Proxy inverso para las APIs de Opencode (prefijo /api)
196
245
  if (req.url.startsWith('/api/')) {
197
246
  const targetPath = req.url.substring(4) // Quita el '/api'
package/bin/init.js CHANGED
@@ -25,7 +25,7 @@ ${bold}${cyan}███████╗██╗ ██╗ ██████
25
25
  ███╔╝ ██║ ██║██║ ██║ ███╔╝
26
26
  ███████╗╚██████╔╝╚██████╔╝███████╗
27
27
  ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝${reset}
28
- ${bold}${yellow} Harness Installer v1.0.11${reset}\n`;
28
+ ${bold}${yellow} Harness Installer v1.0.13${reset}\n`;
29
29
 
30
30
  console.log(banner);
31
31
  console.log(`${bold}${cyan}🔍 Detectando entorno de trabajo...${reset}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zugzbot",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Fácil instalador del arnés SDD de Zugzbot para proyectos OpenCode",
5
5
  "type": "module",
6
6
  "bin": {