ragfly-cli 1.17.2__tar.gz → 1.17.3__tar.gz

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.
Files changed (25) hide show
  1. {ragfly_cli-1.17.2/ragfly_cli.egg-info → ragfly_cli-1.17.3}/PKG-INFO +1 -1
  2. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/pyproject.toml +1 -1
  3. ragfly_cli-1.17.3/ragfly_cli/__init__.py +1 -0
  4. ragfly_cli-1.17.3/ragfly_cli/_runtime.py +15 -0
  5. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/cli.py +97 -49
  6. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/oop/http_client.py +14 -1
  7. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3/ragfly_cli.egg-info}/PKG-INFO +1 -1
  8. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli.egg-info/SOURCES.txt +1 -0
  9. ragfly_cli-1.17.2/ragfly_cli/__init__.py +0 -1
  10. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/LICENSE +0 -0
  11. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/README.md +0 -0
  12. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/__main__.py +0 -0
  13. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/_http.py +0 -0
  14. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/cloud_commands.py +0 -0
  15. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/config.py +0 -0
  16. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/grupo_activo.py +0 -0
  17. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/keyring_store.py +0 -0
  18. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/oop/__init__.py +0 -0
  19. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/oop/cli_command.py +0 -0
  20. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli/version_check.py +0 -0
  21. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli.egg-info/dependency_links.txt +0 -0
  22. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli.egg-info/entry_points.txt +0 -0
  23. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli.egg-info/requires.txt +0 -0
  24. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/ragfly_cli.egg-info/top_level.txt +0 -0
  25. {ragfly_cli-1.17.2 → ragfly_cli-1.17.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragfly-cli
3
- Version: 1.17.2
3
+ Version: 1.17.3
4
4
  Summary: RAGfly CLI — operate RAGfly from the terminal and CI (login + cloud API). Lightweight, no desktop dependencies.
5
5
  Author: CAB Ltda
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ragfly-cli"
7
- version = "1.17.2"
7
+ version = "1.17.3"
8
8
  description = "RAGfly CLI — operate RAGfly from the terminal and CI (login + cloud API). Lightweight, no desktop dependencies."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1 @@
1
+ __version__ = "1.17.3"
@@ -0,0 +1,15 @@
1
+ """Estado de runtime compartido por el CLI (flags globales).
2
+
3
+ Hoy solo lleva el flag `-v/--verbose`, que la capa HTTP (`oop/http_client.py`)
4
+ consulta para loggear método+URL+status de cada request a **stderr** — nunca a
5
+ stdout, para no contaminar la salida `-o json` que se pipea a `jq`.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ VERBOSE: bool = False
11
+
12
+
13
+ def set_verbose(value: bool) -> None:
14
+ global VERBOSE
15
+ VERBOSE = bool(value)
@@ -1,24 +1,27 @@
1
1
  """
2
- CLI principal de RAGfly — Cliente local y Cloud.
2
+ CLI principal de RAGfly — paquete `ragfly-cli` (el binario `ragfly`).
3
3
 
4
- Comandos locales:
4
+ Comandos:
5
5
  ragfly version — Versión del cliente
6
- ragfly estado — Estado de la BD local
7
- ragfly setup — Configuración inicial
8
- ragfly escanear — Escanear directorio de documentos
9
- ragfly procesar — Procesar documentos (CHUNKEAR; el cloud vectoriza)
10
- ragfly sync — Sincronizar con el cloud
11
- ragfly api — API local para integración
12
- ragfly gui — Interfaz gráfica nativa (PySide6)
13
-
14
- Comandos cloud:
15
6
  ragfly login — Autenticar contra el cloud
16
7
  ragfly logout — Cerrar sesión
17
8
  ragfly cloud me — Ver contexto activo
9
+ ragfly cloud grupo listar/cambiar/limpiar
10
+ ragfly cloud api-key crear/listar/revocar
18
11
  ragfly cloud documento listar/ver
19
- ragfly cloud espacio listar/ver
20
- ragfly cloud cola ver/ejecuciones
12
+ ragfly cloud espacio listar/ver
13
+ ragfly cloud cola ver/ejecuciones
21
14
  ragfly cloud habilidad listar/ver/ejecutar
15
+ ragfly cloud catalogo
16
+ ragfly cloud buscar
17
+ ragfly cloud chat preguntar
18
+
19
+ Las operaciones de filesystem local (`ragfly local scan/sync/daemon`) NO viven
20
+ en este paquete: vienen con RAGfly Desktop.
21
+
22
+ Flags globales: `-o {tabla,json,csv,id}` (según comando) y `-v/--verbose`
23
+ (método+URL+status de cada request, a stderr). `-v` va antes del subcomando:
24
+ `ragfly -v cloud documento listar`.
22
25
  """
23
26
 
24
27
  import json
@@ -30,21 +33,50 @@ from rich.console import Console
30
33
  from rich.table import Table
31
34
  from rich.panel import Panel
32
35
 
33
- from . import __version__
36
+ from . import __version__, _runtime
34
37
  from ._http import default_headers
35
38
 
36
39
  console = Console()
37
40
  err_console = Console(stderr=True)
38
41
 
39
42
 
43
+ # ── Salida cruda a stdout (pipe-safe) ────────────────────────────────────────
44
+ # Rich (`console.print`) interpreta `[...]` como markup y hace soft-wrap al ancho
45
+ # de la terminal: ambos rompen el JSON/CSV cuando se pipea a `jq` u otra tool.
46
+ # Para datos legibles por máquina escribimos directo a stdout con click.echo.
47
+
48
+ def _emit_json(obj) -> None:
49
+ """Imprime JSON crudo a stdout, sin pasar por Rich. Seguro para `| jq`."""
50
+ click.echo(json.dumps(obj, indent=2, ensure_ascii=False, default=str))
51
+
52
+
53
+ def _emit_ids(items, *keys: str) -> None:
54
+ """Imprime un id por línea (el primer `key` presente en cada item). Para
55
+ `-o id` en pipes. Acepta un dict suelto (un solo recurso) o una lista."""
56
+ if isinstance(items, dict):
57
+ items = [items]
58
+ for it in items or []:
59
+ if not isinstance(it, dict):
60
+ click.echo(str(it))
61
+ continue
62
+ for k in keys:
63
+ val = it.get(k)
64
+ if val not in (None, ""):
65
+ click.echo(str(val))
66
+ break
67
+
68
+
40
69
  # ════════════════════════════════════════════════════════════════════════════
41
70
  # Grupo raíz
42
71
  # ════════════════════════════════════════════════════════════════════════════
43
72
 
44
73
  @click.group()
45
- def app():
46
- """RAGfly — Cliente local y Cloud."""
47
- pass
74
+ @click.option("-v", "--verbose", is_flag=True,
75
+ help="Muestra método+URL+status de cada request (a stderr).")
76
+ def app(verbose: bool):
77
+ """RAGfly — paquete `ragfly-cli` (binario `ragfly`)."""
78
+ if verbose:
79
+ _runtime.set_verbose(True)
48
80
 
49
81
 
50
82
  # ════════════════════════════════════════════════════════════════════════════
@@ -129,7 +161,7 @@ def cloud_me(output: str):
129
161
  data = cmd.protegido(cloud_get, "/auth/me")
130
162
 
131
163
  if output == "json":
132
- console.print(json.dumps(data, indent=2, ensure_ascii=False))
164
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False))
133
165
  return
134
166
 
135
167
  console.print()
@@ -173,7 +205,7 @@ def cloud_grupo_listar(output: str):
173
205
  activo = get_grupo_activo_local()
174
206
 
175
207
  if output == "json":
176
- console.print(json.dumps({"activo": activo, "grupos": grupos}, indent=2, ensure_ascii=False))
208
+ click.echo(json.dumps({"activo": activo, "grupos": grupos}, indent=2, ensure_ascii=False))
177
209
  return
178
210
 
179
211
  console.print()
@@ -267,7 +299,7 @@ def cloud_api_key_crear(nombre: str, rol: str | None, area: str | None, usuario_
267
299
  data = cmd.protegido(cloud_post, "/auth/api-key", body)
268
300
 
269
301
  if output == "json":
270
- console.print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
302
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False, default=str))
271
303
  return
272
304
 
273
305
  console.print()
@@ -294,7 +326,7 @@ def cloud_api_key_listar(output: str):
294
326
  items = data if isinstance(data, list) else data.get("items", [])
295
327
 
296
328
  if output == "json":
297
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
329
+ click.echo(json.dumps(items, indent=2, ensure_ascii=False, default=str))
298
330
  return
299
331
 
300
332
  console.print()
@@ -350,15 +382,18 @@ def cloud_documento():
350
382
  @click.option("--estado", default=None, help="Filtrar por estado (ej. VECTORIZADO)")
351
383
  @click.option("--limite", default=20, show_default=True)
352
384
  @click.option("--pagina", default=1, show_default=True)
353
- @click.option("-o", "--output", type=click.Choice(["tabla", "json", "csv"]), default="tabla")
385
+ @click.option("-o", "--output", type=click.Choice(["tabla", "json", "csv", "id"]), default="tabla")
354
386
  def cloud_documento_listar(estado: str | None, limite: int, pagina: int, output: str):
355
387
  """Listar documentos del grupo activo."""
356
388
  from .cloud_commands import cloud_get
357
389
  from .oop import CliCommand
358
390
 
359
- params: dict = {"limite": limite, "pagina": pagina}
391
+ # El backend (GET /documentos/paginado) espera limit/page/codigo_estado_doc.
392
+ # FastAPI ignora silenciosamente los params desconocidos, así que enviar
393
+ # limite/pagina/estado se traducía en "sin filtro, 50 por defecto".
394
+ params: dict = {"limit": limite, "page": pagina}
360
395
  if estado:
361
- params["estado"] = estado
396
+ params["codigo_estado_doc"] = estado
362
397
 
363
398
  cmd = CliCommand()
364
399
  data = cmd.protegido(cloud_get, "/documentos/paginado", params=params)
@@ -366,13 +401,17 @@ def cloud_documento_listar(estado: str | None, limite: int, pagina: int, output:
366
401
  items = data.get("items", data) if isinstance(data, dict) else data
367
402
 
368
403
  if output == "json":
369
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
404
+ _emit_json(items)
405
+ return
406
+
407
+ if output == "id":
408
+ _emit_ids(items, "codigo_documento")
370
409
  return
371
410
 
372
411
  if output == "csv":
373
- console.print("codigo,nombre,estado,ubicacion")
412
+ click.echo("codigo,nombre,estado,ubicacion")
374
413
  for d in items:
375
- console.print(
414
+ click.echo(
376
415
  f"{d.get('codigo_documento','')},{d.get('nombre_documento','')}"
377
416
  f",{d.get('codigo_estado_doc','')},{d.get('nombre_ubicacion','')}"
378
417
  )
@@ -417,7 +456,7 @@ def cloud_documento_ver(codigo: str, output: str):
417
456
  data = cmd.protegido(cloud_get, f"/documentos/{codigo}")
418
457
 
419
458
  if output == "json":
420
- console.print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
459
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False, default=str))
421
460
  return
422
461
 
423
462
  console.print()
@@ -449,19 +488,23 @@ def cloud_espacio():
449
488
 
450
489
  @cloud_espacio.command("listar")
451
490
  @click.option("--limite", default=20, show_default=True)
452
- @click.option("-o", "--output", type=click.Choice(["tabla", "json"]), default="tabla")
491
+ @click.option("-o", "--output", type=click.Choice(["tabla", "json", "id"]), default="tabla")
453
492
  def cloud_espacio_listar(limite: int, output: str):
454
493
  """Listar Espacios de Trabajo del grupo activo."""
455
494
  from .cloud_commands import cloud_get
456
495
  from .oop import CliCommand
457
496
 
458
497
  cmd = CliCommand()
459
- data = cmd.protegido(cloud_get, "/espacios-trabajo/paginado", params={"limite": limite})
498
+ data = cmd.protegido(cloud_get, "/espacios-trabajo/paginado", params={"limit": limite})
460
499
 
461
500
  items = data.get("items", data) if isinstance(data, dict) else data
462
501
 
463
502
  if output == "json":
464
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
503
+ _emit_json(items)
504
+ return
505
+
506
+ if output == "id":
507
+ _emit_ids(items, "id_espacio")
465
508
  return
466
509
 
467
510
  console.print()
@@ -495,7 +538,7 @@ def cloud_espacio_ver(id_espacio: int, limite: int, output: str):
495
538
 
496
539
  cmd = CliCommand()
497
540
  # No hay GET /{id} suelto — buscamos en paginado y filtramos
498
- espacios_data = cmd.protegido(cloud_get, "/espacios-trabajo/paginado", params={"limite": 200})
541
+ espacios_data = cmd.protegido(cloud_get, "/espacios-trabajo/paginado", params={"limit": 200})
499
542
  items_esp = espacios_data.get("items", espacios_data) if isinstance(espacios_data, dict) else espacios_data
500
543
  espacio = next((e for e in items_esp if e.get("id_espacio") == id_espacio), None)
501
544
  if not espacio:
@@ -503,12 +546,11 @@ def cloud_espacio_ver(id_espacio: int, limite: int, output: str):
503
546
  docs_data = cmd.protegido(
504
547
  cloud_get,
505
548
  f"/espacios-trabajo/{id_espacio}/documentos/paginado",
506
- params={"limite": limite},
549
+ params={"limit": limite},
507
550
  )
508
551
 
509
552
  if output == "json":
510
- console.print(json.dumps({"espacio": espacio, "documentos": docs_data},
511
- indent=2, ensure_ascii=False, default=str))
553
+ _emit_json({"espacio": espacio, "documentos": docs_data})
512
554
  return
513
555
 
514
556
  console.print()
@@ -558,11 +600,13 @@ def cloud_cola_ver(proceso: str | None, estado: str | None, limite: int, output:
558
600
  from .cloud_commands import cloud_get
559
601
  from .oop import CliCommand
560
602
 
561
- params: dict = {"limite": limite}
562
- if proceso:
563
- params["proceso"] = proceso
603
+ # Backend GET /cola-estados-docs/paginado → page/limit/estado_cola/q.
604
+ params: dict = {"limit": limite}
564
605
  if estado:
565
- params["estado"] = estado
606
+ params["estado_cola"] = estado
607
+ if proceso:
608
+ # El paginado no filtra por proceso; lo usamos como búsqueda libre (q).
609
+ params["q"] = proceso
566
610
 
567
611
  cmd = CliCommand()
568
612
  data = cmd.protegido(cloud_get, "/cola-estados-docs/paginado", params=params)
@@ -570,7 +614,7 @@ def cloud_cola_ver(proceso: str | None, estado: str | None, limite: int, output:
570
614
  items = data.get("items", data) if isinstance(data, dict) else data
571
615
 
572
616
  if output == "json":
573
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
617
+ click.echo(json.dumps(items, indent=2, ensure_ascii=False, default=str))
574
618
  return
575
619
 
576
620
  console.print()
@@ -613,12 +657,12 @@ def cloud_cola_ejecuciones(limite: int, output: str):
613
657
  from .oop import CliCommand
614
658
 
615
659
  cmd = CliCommand()
616
- data = cmd.protegido(cloud_get, "/cola-estados-docs/ejecuciones", params={"limite": limite})
660
+ data = cmd.protegido(cloud_get, "/cola-estados-docs/ejecuciones", params={"limit": limite})
617
661
 
618
662
  items = data.get("items", data) if isinstance(data, dict) else data
619
663
 
620
664
  if output == "json":
621
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
665
+ click.echo(json.dumps(items, indent=2, ensure_ascii=False, default=str))
622
666
  return
623
667
 
624
668
  console.print()
@@ -656,7 +700,7 @@ def cloud_habilidad():
656
700
 
657
701
 
658
702
  @cloud_habilidad.command("listar")
659
- @click.option("-o", "--output", type=click.Choice(["tabla", "json"]), default="tabla")
703
+ @click.option("-o", "--output", type=click.Choice(["tabla", "json", "id"]), default="tabla")
660
704
  def cloud_habilidad_listar(output: str):
661
705
  """Listar todas las habilidades disponibles."""
662
706
  from .cloud_commands import cloud_get
@@ -666,7 +710,11 @@ def cloud_habilidad_listar(output: str):
666
710
  items = cmd.protegido(cloud_get, "/habilidades")
667
711
 
668
712
  if output == "json":
669
- console.print(json.dumps(items, indent=2, ensure_ascii=False, default=str))
713
+ _emit_json(items)
714
+ return
715
+
716
+ if output == "id":
717
+ _emit_ids(items, "codigo_habilidad")
670
718
  return
671
719
 
672
720
  console.print()
@@ -701,7 +749,7 @@ def cloud_habilidad_ver(codigo: str, output: str):
701
749
  h = cmd.protegido(cloud_get, f"/habilidades/{codigo}")
702
750
 
703
751
  if output == "json":
704
- console.print(json.dumps(h, indent=2, ensure_ascii=False, default=str))
752
+ click.echo(json.dumps(h, indent=2, ensure_ascii=False, default=str))
705
753
  return
706
754
 
707
755
  console.print()
@@ -755,7 +803,7 @@ def cloud_habilidad_ejecutar(
755
803
  resultado = cmd.protegido(cloud_post, f"/habilidades/{codigo}/ejecutar", body=body)
756
804
 
757
805
  if output == "json":
758
- console.print(json.dumps(resultado, indent=2, ensure_ascii=False, default=str))
806
+ click.echo(json.dumps(resultado, indent=2, ensure_ascii=False, default=str))
759
807
  return
760
808
 
761
809
  # Contrato uniforme (SobreEjecucion): codigo_proceso + detalle.n_items_cola.
@@ -801,7 +849,7 @@ def cloud_catalogo(tipo: str, output: str):
801
849
  data = cmd.protegido(cloud_get, "/catalogo", params={"tipo": tipo})
802
850
 
803
851
  if output == "json":
804
- console.print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
852
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False, default=str))
805
853
  return
806
854
 
807
855
  funciones = data.get("funciones", [])
@@ -881,7 +929,7 @@ def cloud_buscar(
881
929
  data = cmd.protegido(cloud_post, "/documentos/buscar-semantico", body=body)
882
930
 
883
931
  if output == "json":
884
- console.print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
932
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False, default=str))
885
933
  return
886
934
 
887
935
  items = data.get("resultados") or data.get("items") or data if isinstance(data, list) else (
@@ -981,7 +1029,7 @@ def cloud_chat_preguntar(
981
1029
  raise CloudError(f"No se pudo conectar al servidor: {e}", exit_code=2)
982
1030
 
983
1031
  if output == "json":
984
- console.print(json.dumps({
1032
+ click.echo(json.dumps({
985
1033
  "id_conversacion": id_conversacion,
986
1034
  "respuesta": "".join(partes),
987
1035
  **meta,
@@ -20,10 +20,13 @@ Ejemplo:
20
20
 
21
21
  from __future__ import annotations
22
22
 
23
+ import sys
23
24
  from typing import Any, Optional
24
25
 
25
26
  import httpx
26
27
 
28
+ from ragfly_cli import _runtime
29
+
27
30
  # Import diferido para evitar ciclo
28
31
  from ragfly_cli.cloud_commands import (
29
32
  CLOUD_URL,
@@ -75,7 +78,17 @@ class CloudHttpClient:
75
78
  if is_write and method != "DELETE":
76
79
  kwargs["json"] = body or {}
77
80
 
78
- r = httpx.request(method, f"{self.url}{path}", **kwargs)
81
+ url_full = f"{self.url}{path}"
82
+ if _runtime.VERBOSE:
83
+ qs = httpx.QueryParams(params or {})
84
+ sufijo = f"?{qs}" if str(qs) else ""
85
+ print(f"→ {method} {url_full}{sufijo}", file=sys.stderr)
86
+
87
+ r = httpx.request(method, url_full, **kwargs)
88
+
89
+ if _runtime.VERBOSE:
90
+ print(f"← {r.status_code} {r.reason_phrase}", file=sys.stderr)
91
+
79
92
  r.raise_for_status()
80
93
  if r.status_code == 204 or not r.content:
81
94
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragfly-cli
3
- Version: 1.17.2
3
+ Version: 1.17.3
4
4
  Summary: RAGfly CLI — operate RAGfly from the terminal and CI (login + cloud API). Lightweight, no desktop dependencies.
5
5
  Author: CAB Ltda
6
6
  License: MIT
@@ -4,6 +4,7 @@ pyproject.toml
4
4
  ragfly_cli/__init__.py
5
5
  ragfly_cli/__main__.py
6
6
  ragfly_cli/_http.py
7
+ ragfly_cli/_runtime.py
7
8
  ragfly_cli/cli.py
8
9
  ragfly_cli/cloud_commands.py
9
10
  ragfly_cli/config.py
@@ -1 +0,0 @@
1
- __version__ = "1.17.2"
File without changes
File without changes
File without changes