operx-cli 0.2.1__tar.gz → 0.2.2__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 (48) hide show
  1. {operx_cli-0.2.1 → operx_cli-0.2.2}/PKG-INFO +1 -1
  2. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/__init__.py +1 -1
  3. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/app.py +1 -1
  4. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/account.py +2 -1
  5. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/shell.py +14 -3
  6. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/PKG-INFO +1 -1
  7. {operx_cli-0.2.1 → operx_cli-0.2.2}/pyproject.toml +1 -1
  8. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_app.py +3 -0
  9. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_shell.py +43 -0
  10. {operx_cli-0.2.1 → operx_cli-0.2.2}/README.md +0 -0
  11. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/AGENTES.md +0 -0
  12. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/agent_guide.py +0 -0
  13. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/browser_login.py +0 -0
  14. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/client.py +0 -0
  15. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/__init__.py +0 -0
  16. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/common.py +0 -0
  17. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/inventario.py +0 -0
  18. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/lecturas.py +0 -0
  19. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/ordenes.py +0 -0
  20. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/personas.py +0 -0
  21. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/raw.py +0 -0
  22. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/registros.py +0 -0
  23. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/commands/search.py +0 -0
  24. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/lookup.py +0 -0
  25. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/output.py +0 -0
  26. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/settings.py +0 -0
  27. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/spreadsheet.py +0 -0
  28. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/values.py +0 -0
  29. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli/welcome.py +0 -0
  30. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/SOURCES.txt +0 -0
  31. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/dependency_links.txt +0 -0
  32. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/entry_points.txt +0 -0
  33. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/requires.txt +0 -0
  34. {operx_cli-0.2.1 → operx_cli-0.2.2}/operx_cli.egg-info/top_level.txt +0 -0
  35. {operx_cli-0.2.1 → operx_cli-0.2.2}/setup.cfg +0 -0
  36. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_agentes.py +0 -0
  37. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_client.py +0 -0
  38. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_inventario_lecturas.py +0 -0
  39. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_login.py +0 -0
  40. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_lookup.py +0 -0
  41. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_ordenes.py +0 -0
  42. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_output.py +0 -0
  43. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_personas.py +0 -0
  44. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_registros.py +0 -0
  45. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_settings.py +0 -0
  46. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_spreadsheet.py +0 -0
  47. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_values.py +0 -0
  48. {operx_cli-0.2.1 → operx_cli-0.2.2}/tests/test_welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: operx-cli
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -2,4 +2,4 @@
2
2
  API (backend/users/api_allowlist.py) from a terminal, with a personal API
3
3
  token."""
4
4
 
5
- __version__ = "0.2.1"
5
+ __version__ = "0.2.2"
@@ -136,7 +136,7 @@ app.add_typer(personas.app, name="personas")
136
136
 
137
137
  @app.command()
138
138
  def agentes(ctx: typer.Context):
139
- """La guía para agentes de IA (Claude, ChatGPT, Copilot): cómo usar operx bien, con cada comando y sus opciones."""
139
+ """La guía para que un agente de IA (Claude, ChatGPT…) use operx bien."""
140
140
  typer.echo(guide_text(ctx.find_root().command))
141
141
 
142
142
 
@@ -100,5 +100,6 @@ def cuenta(ctx: typer.Context, as_json: JsonOption = False):
100
100
  "Rol": [role for role in roles if role],
101
101
  "Productos": [PRODUCT_LABELS.get(product, product) for product in me.get("products") or []],
102
102
  "Perfil": session.profile,
103
- "Dirección": session.address(),
103
+ # The API's address, the same for every company (not acme.operx.pro, the app's).
104
+ "API": session.address(),
104
105
  }, "tabla")
@@ -13,6 +13,8 @@ import shlex
13
13
 
14
14
  import typer
15
15
  from rich.console import Console
16
+ from rich.padding import Padding
17
+ from rich.table import Table
16
18
  from rich.text import Text
17
19
 
18
20
  from . import settings
@@ -21,8 +23,12 @@ PROMPT = "operx › "
21
23
  STOP_WORDS = ("salir", "exit", "quit")
22
24
  HELP_WORDS = ("/ayuda", "ayuda", "/help", "help", "?")
23
25
  CLEAR_WORDS = ("limpiar", "/limpiar", "clear", "cls")
24
- # What the prompt offers besides the commands: leaving, and the list of them.
25
- SHELL_WORDS = [("salir", "Termina esta sesión. No borra tu token."), ("ayuda", "Muestra los comandos.")]
26
+ # What the prompt offers besides the commands, with the other words that do the same.
27
+ SHELL_WORDS = [
28
+ ("limpiar", "Limpia la pantalla. También: clear, cls."),
29
+ ("salir", "Termina esta sesión. No borra tu token. También: exit, quit, Ctrl+D."),
30
+ ("ayuda", "Muestra los comandos. También: help, ?."),
31
+ ]
26
32
  AMBER = "#fbbf24"
27
33
 
28
34
 
@@ -111,8 +117,13 @@ def spanish_usage_error(error):
111
117
  def print_help(root, console):
112
118
  console.print(Text("Comandos", style=f"bold {AMBER}"))
113
119
  commands = [(name, _first_line(command.help)) for name, command in root.commands.items() if _visible(command)]
120
+ # Two columns: on a narrow screen a long description wraps inside its own.
121
+ table = Table.grid(padding=(0, 2))
122
+ table.add_column(style="bold", no_wrap=True)
123
+ table.add_column()
114
124
  for name, help_text in commands + SHELL_WORDS:
115
- console.print(Text.assemble((" " + name.ljust(12), "bold"), help_text))
125
+ table.add_row(name, help_text)
126
+ console.print(Padding(table, (0, 0, 0, 2)))
116
127
  console.print(Text("Escribe un comando con --help para ver sus opciones.", style="dim"))
117
128
 
118
129
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: operx-cli
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "operx-cli"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  description = "La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -70,6 +70,9 @@ def test_cuenta_shows_who_and_where(signed_in):
70
70
  assert result.exit_code == 0, result.output
71
71
  for text in ("Ana Ruiz", "ana@acme.co", "Acme S.A.S.", "Administrador", "Trabajos, Personas", "https://api.operx.pro"):
72
72
  assert text in result.output
73
+ # The API's address, the same for every company: not the company's web address.
74
+ api_line = next(line for line in result.output.splitlines() if "https://api.operx.pro" in line)
75
+ assert api_line.startswith("API ")
73
76
 
74
77
 
75
78
  def test_buscar_lists_what_the_top_bar_finds(signed_in):
@@ -206,6 +206,49 @@ def test_ayuda_lists_the_commands(capsys):
206
206
  assert "entrar" not in out
207
207
 
208
208
 
209
+ def test_ayuda_lists_every_word_the_prompt_understands(capsys):
210
+ shell(FakeApi({}), "ayuda")
211
+ out = capsys.readouterr().out
212
+ for word in ("salir", "exit", "quit", "Ctrl+D", "limpiar", "clear", "cls", "ayuda", "help", "?"):
213
+ assert word in out
214
+
215
+
216
+ def test_limpiar_is_offered_while_typing():
217
+ assert "limpiar" in names(suggestions(ROOT, "lim"))
218
+
219
+
220
+ def test_ayuda_keeps_a_long_description_in_its_own_column_on_a_narrow_screen():
221
+ import io
222
+
223
+ from rich.console import Console
224
+
225
+ from operx_cli.shell import print_help
226
+
227
+ out = io.StringIO()
228
+ print_help(ROOT, Console(file=out, width=60, force_terminal=False, color_system=None))
229
+ lines = out.getvalue().splitlines()
230
+ column = lines[1].index("Entra con tu cuenta")
231
+ wrapped = [line for line in lines[1:-1] if line[:column].strip() == ""]
232
+
233
+ assert wrapped # at 60 columns some descriptions take two lines
234
+ for line in wrapped:
235
+ assert line[column - 1] == " " and line[column] != " "
236
+
237
+
238
+ def test_every_description_fits_one_line_on_a_common_screen():
239
+ import io
240
+
241
+ from rich.console import Console
242
+
243
+ from operx_cli.shell import print_help
244
+
245
+ out = io.StringIO()
246
+ print_help(ROOT, Console(file=out, width=120, force_terminal=False, color_system=None))
247
+ lines = out.getvalue().splitlines()[1:-1]
248
+
249
+ assert all(line[:2] == " " and line[2] != " " for line in lines)
250
+
251
+
209
252
  def test_the_old_names_stay_out_of_what_is_offered(capsys):
210
253
  shell(FakeApi({}), "ayuda")
211
254
  assert "entrar" not in capsys.readouterr().out
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes