zugzbot 1.0.15 → 1.0.17

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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>client</title>
8
- <script type="module" crossorigin src="/assets/index-CVh0OG8j.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CBm0KdaD.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-GxkFc3Mh.css">
10
10
  </head>
11
11
  <body>
@@ -796,9 +796,26 @@ export default function App() {
796
796
  const data = await res.json()
797
797
  if (currentSessionId && data[currentSessionId]) {
798
798
  const status = data[currentSessionId]
799
- const isBusy = status === 'thinking' || status === 'running_tools' || status === 'busy'
799
+ const isBusy = status === 'thinking' || status === 'running_tools' || status === 'busy' || status === 'running' || status === 'executing' || status === 'processing'
800
800
 
801
- if (isBusy) {
801
+ // Heurística de doble capa: buscar si la última parte de herramienta en el historial sigue activa
802
+ let hasRunningTool = false
803
+ if (messages.length > 0) {
804
+ const lastMsg = messages[messages.length - 1]
805
+ if (lastMsg.info.role === 'assistant' && lastMsg.parts) {
806
+ const lastToolPart = [...lastMsg.parts].reverse().find(p => p.type === 'tool')
807
+ if (lastToolPart && lastToolPart.state) {
808
+ const toolStatus = lastToolPart.state.status
809
+ if (toolStatus === 'running' || toolStatus === 'thinking' || toolStatus === 'processing' || toolStatus === 'active') {
810
+ hasRunningTool = true
811
+ }
812
+ }
813
+ }
814
+ }
815
+
816
+ const isReallyBusy = isBusy || hasRunningTool
817
+
818
+ if (isReallyBusy) {
802
819
  setIsProcessing(prev => {
803
820
  if (isAbortingRef.current) return false
804
821
  if (!prev) {
@@ -1050,6 +1067,24 @@ export default function App() {
1050
1067
  [newSess.id]: projectId
1051
1068
  }))
1052
1069
 
1070
+ // Si es un subproyecto (no la raíz), enviamos el anclaje de sistema de inmediato para orientar a la IA
1071
+ let anchorPrefix = ''
1072
+ if (project && project.id !== 'workspace_raiz') {
1073
+ anchorPrefix = `[SISTEMA: Directorio de trabajo del proyecto: ${project.path}. Por favor, realiza todas tus operaciones de archivos, edits, y ejecuciones de comandos de bash estrictamente dentro de esta subcarpeta usando el parámetro "workdir" o comandos relativos a la misma. No escribas archivos en la raíz del repositorio central de Zugzbot a menos que sea explícitamente necesario. Comienza saludando al usuario y confirmando que estás listo para trabajar en este subproyecto.]`
1074
+ }
1075
+
1076
+ if (anchorPrefix) {
1077
+ const bodyPayload = {
1078
+ parts: [{ type: 'text', text: anchorPrefix }],
1079
+ agent: selectedAgent || 'sdd-orchestrator'
1080
+ }
1081
+ await fetch(`/api/session/${newSess.id}/prompt_async`, {
1082
+ method: 'POST',
1083
+ headers: { 'Content-Type': 'application/json' },
1084
+ body: JSON.stringify(bodyPayload)
1085
+ })
1086
+ }
1087
+
1053
1088
  // Redirigir a la vista de chat
1054
1089
  navigateTo('/')
1055
1090
  } else {
@@ -2366,7 +2401,7 @@ export default function App() {
2366
2401
  )}
2367
2402
 
2368
2403
  {/* INDICADOR DE CARGA EN TIEMPO REAL DEL AGENTE */}
2369
- {isProcessing && messages.length > 0 && messages[messages.length - 1].info.role === 'user' && (
2404
+ {isProcessing && (
2370
2405
  <div className="flex gap-4 max-w-4xl mx-auto justify-start">
2371
2406
  <div className="h-8 w-8 rounded-full border border-[#2e2e33] bg-[#18181b] flex items-center justify-center text-[#fafafa] shrink-0">
2372
2407
  <Bot size={16} className="animate-spin text-emerald-400" style={{ animationDuration: '4s' }} />
@@ -2441,12 +2476,12 @@ export default function App() {
2441
2476
  </div>
2442
2477
  </div>
2443
2478
 
2444
- {/* Input Textarea principal */}
2479
+ {/* Input Textarea principal */}
2445
2480
  <div className="relative border border-[#27272a] focus-within:border-[#3f3f46] rounded-xl bg-[#0c0c0e] overflow-hidden shadow-lg transition duration-200">
2446
2481
  <textarea
2447
2482
  value={inputValue}
2448
2483
  onChange={e => setInputValue(e.target.value)}
2449
- disabled={!currentSessionId}
2484
+ disabled={!currentSessionId || isProcessing}
2450
2485
  onKeyDown={e => {
2451
2486
  if (e.key === 'Enter' && !e.shiftKey) {
2452
2487
  e.preventDefault()
@@ -2456,6 +2491,8 @@ export default function App() {
2456
2491
  placeholder={
2457
2492
  !currentSessionId
2458
2493
  ? "Debe haber una sesión activa de Opencode para enviar prompts. Por favor, inicia conexión o crea una sesión."
2494
+ : isProcessing
2495
+ ? "El agente está procesando tu solicitud... Por favor, espera a que termine o haz clic en 'Abortar' para cancelar."
2459
2496
  : inputValue.startsWith('/')
2460
2497
  ? "Escribe los argumentos para el comando... (ej. /loop Crear login)"
2461
2498
  : `Instrucción para ${activeInstance?.name || 'Opencode'} usando ${AVAILABLE_AGENTS.find(a => a.id === selectedAgent)?.name || selectedAgent}... (Escribe / para ver comandos, Shift+Enter para nueva línea)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zugzbot",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Fácil instalador del arnés SDD de Zugzbot para proyectos OpenCode",
5
5
  "type": "module",
6
6
  "bin": {