lisa-cli 0.3.0__tar.gz → 0.4.0__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. {lisa_cli-0.3.0/src/lisa_cli.egg-info → lisa_cli-0.4.0}/PKG-INFO +9 -9
  2. lisa_cli-0.4.0/pyproject.toml +177 -0
  3. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/entry.py +13 -7
  4. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/main.py +410 -147
  5. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/render.py +13 -4
  6. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/transport.py +74 -23
  7. lisa_cli-0.4.0/src/hosts/cli/update.py +624 -0
  8. {lisa_cli-0.3.0 → lisa_cli-0.4.0/src/lisa_cli.egg-info}/PKG-INFO +9 -9
  9. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/lisa_cli.egg-info/SOURCES.txt +12 -1
  10. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/lisa_cli.egg-info/requires.txt +8 -8
  11. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_approval_panel.py +1 -2
  12. lisa_cli-0.4.0/tests/test_changed_coverage.py +158 -0
  13. lisa_cli-0.4.0/tests/test_check_coverage_gate.py +108 -0
  14. lisa_cli-0.4.0/tests/test_check_docs.py +227 -0
  15. lisa_cli-0.4.0/tests/test_direct_io_policy.py +134 -0
  16. lisa_cli-0.4.0/tests/test_error_text_escaping.py +118 -0
  17. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_group_resolution.py +48 -5
  18. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_last_command.py +11 -4
  19. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_models_command.py +4 -6
  20. lisa_cli-0.4.0/tests/test_no_locals_dump.py +69 -0
  21. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_pack_update.py +55 -4
  22. lisa_cli-0.4.0/tests/test_profile_env_fallback.py +99 -0
  23. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_profile_option.py +23 -8
  24. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_prompt_decisions.py +7 -19
  25. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_prompt_transport.py +98 -6
  26. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_render_catalogs.py +3 -2
  27. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_streaming.py +1 -1
  28. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_update_command.py +136 -20
  29. lisa_cli-0.4.0/tests/test_update_policy.py +550 -0
  30. lisa_cli-0.4.0/tests/test_update_policy_uv.py +497 -0
  31. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_verify_command.py +115 -19
  32. lisa_cli-0.4.0/tests/test_version_output.py +71 -0
  33. lisa_cli-0.3.0/pyproject.toml +0 -75
  34. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/LICENSE +0 -0
  35. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/setup.cfg +0 -0
  36. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/__init__.py +0 -0
  37. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/__init__.py +0 -0
  38. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/hosts/cli/expand.py +0 -0
  39. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/lisa_cli.egg-info/dependency_links.txt +0 -0
  40. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/lisa_cli.egg-info/entry_points.txt +0 -0
  41. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/src/lisa_cli.egg-info/top_level.txt +0 -0
  42. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_prompt_command.py +0 -0
  43. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_prompt_entry.py +0 -0
  44. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_prompt_expand.py +0 -0
  45. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_render_models.py +1 -1
  46. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_restart.py +0 -0
  47. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_runtime_teardown.py +0 -0
  48. {lisa_cli-0.3.0 → lisa_cli-0.4.0}/tests/test_transport_stage.py +0 -0
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lisa-cli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Terminal CLI for the Lisa Harness
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.11
7
7
  License-File: LICENSE
8
- Requires-Dist: lisa-harness-runtime
9
- Requires-Dist: lisa-harness-kernel
10
- Requires-Dist: lisa-harness-sdk
11
- Requires-Dist: lisa-harness-mcp-servers
12
- Requires-Dist: lisa-pack-core
13
- Requires-Dist: lisa-pack-introspect
14
- Requires-Dist: lisa-pack-memory
15
- Requires-Dist: lisa-pack-recovery
8
+ Requires-Dist: lisa-harness-runtime>=0.5.2
9
+ Requires-Dist: lisa-harness-kernel>=0.5.2
10
+ Requires-Dist: lisa-harness-sdk>=0.5.2
11
+ Requires-Dist: lisa-harness-mcp-servers>=0.5.2
12
+ Requires-Dist: lisa-pack-core>=0.5.2
13
+ Requires-Dist: lisa-pack-introspect>=0.5.2
14
+ Requires-Dist: lisa-pack-memory>=0.5.2
15
+ Requires-Dist: lisa-pack-recovery>=0.5.2
16
16
  Requires-Dist: openai>=1.30.0
17
17
  Requires-Dist: rich>=13.7.0
18
18
  Requires-Dist: typer>=0.12.3
@@ -0,0 +1,177 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.setuptools.packages.find]
6
+ where = ["src"]
7
+
8
+ [project]
9
+ name = "lisa-cli"
10
+ version = "0.4.0"
11
+ description = "Terminal CLI for the Lisa Harness"
12
+ requires-python = ">=3.11"
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ dependencies = [
16
+ "lisa-harness-runtime>=0.5.2",
17
+ "lisa-harness-kernel>=0.5.2",
18
+ "lisa-harness-sdk>=0.5.2",
19
+ "lisa-harness-mcp-servers>=0.5.2",
20
+ "lisa-pack-core>=0.5.2",
21
+ "lisa-pack-introspect>=0.5.2",
22
+ "lisa-pack-memory>=0.5.2",
23
+ "lisa-pack-recovery>=0.5.2",
24
+ "openai>=1.30.0",
25
+ "rich>=13.7.0",
26
+ "typer>=0.12.3",
27
+ "pyyaml>=6.0",
28
+ "httpx>=0.27.0",
29
+ "pydantic>=2.7.0",
30
+ "python-dotenv>=1.0.0",
31
+ ]
32
+
33
+ [project.scripts]
34
+ lisa = "hosts.cli.main:main"
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "pyinstaller>=6.10.0",
39
+ "pytest>=8.0.0",
40
+ "pytest-asyncio>=0.23.0",
41
+ "ruff>=0.8.0",
42
+ "types-PyYAML>=6.0",
43
+ ]
44
+ # Interactive no-args `lisa prompt` editor: single-box input with
45
+ # history. Without the extra the plain EOF-terminated reader is used.
46
+ prompt = ["prompt-toolkit>=3.0"]
47
+
48
+ [tool.pytest.ini_options]
49
+ pythonpath = ["src"]
50
+ testpaths = ["tests"]
51
+ markers = [
52
+ "live: hits real external signal or provider APIs and prints a tester-visible summary",
53
+ "integration: multi-module in-process test; may require local services",
54
+ "eval: deterministic agent regression evals (no model calls, no I/O)",
55
+ ]
56
+
57
+ [tool.coverage.run]
58
+ branch = true
59
+ relative_files = true
60
+ source = ["src"]
61
+ omit = [
62
+ "*/tests/*",
63
+ "*/test_*.py",
64
+ "*/conftest.py",
65
+ ]
66
+ source_pkgs = ["hosts.cli"]
67
+
68
+ [tool.coverage.paths]
69
+ source = [
70
+ "src",
71
+ "*/src",
72
+ ]
73
+
74
+ [tool.coverage.report]
75
+ show_missing = true
76
+ skip_covered = true
77
+ fail_under = 85
78
+ exclude_also = [
79
+ ".*/tests/.*",
80
+ ".*/test_[^/]*\\.py$",
81
+ ]
82
+
83
+ [tool.ruff]
84
+ line-length = 100
85
+ target-version = "py311"
86
+ extend-exclude = ["vulture_allowlist.py"]
87
+
88
+ [tool.ruff.lint]
89
+ select = [
90
+ "E",
91
+ "F",
92
+ "I",
93
+ "UP",
94
+ "B",
95
+ "SIM",
96
+ "PL",
97
+ "C90",
98
+ "RET",
99
+ "RUF",
100
+ "W",
101
+ "YTT",
102
+ "C4",
103
+ "PERF",
104
+ "PIE",
105
+ "FURB",
106
+ "G",
107
+ ]
108
+ ignore = ["PLR0913", "PLC0415", "RUF001", "RUF002", "RUF003"]
109
+
110
+ [tool.ruff.lint.per-file-ignores]
111
+ "**/tests/**" = ["PLC0415", "PLR2004"]
112
+ "**/hosts/cli/main.py" = ["E402", "PLC0415", "PLR0917"]
113
+ "**/hosts/cli/render.py" = ["PLC0415"]
114
+ "**/hosts/cli/entry.py" = ["PLC0415", "RUF001"]
115
+
116
+ [tool.ruff.lint.mccabe]
117
+ max-complexity = 10
118
+
119
+ [tool.ruff.lint.pylint]
120
+ max-returns = 6
121
+ max-branches = 12
122
+ max-statements = 50
123
+ max-locals = 15
124
+
125
+ [tool.ruff.format]
126
+ line-ending = "lf"
127
+
128
+ [tool.mypy]
129
+ python_version = "3.11"
130
+ files = ["src/hosts/cli"]
131
+ mypy_path = ["$MYPY_CONFIG_FILE_DIR/src"]
132
+ explicit_package_bases = true
133
+ strict = true
134
+ warn_unused_ignores = true
135
+ warn_redundant_casts = true
136
+ warn_return_any = true
137
+ no_implicit_optional = true
138
+ check_untyped_defs = true
139
+ disallow_untyped_defs = true
140
+ disallow_incomplete_defs = true
141
+ exclude = ["vulture_allowlist.py", '(^|/)(tests|test_[^/]*\.py$)']
142
+
143
+ [tool.vulture]
144
+ paths = ["src/hosts/cli", "vulture_allowlist.py"]
145
+ min_confidence = 80
146
+ exclude = [
147
+ "**/tests/",
148
+ "**/test_*.py",
149
+ "**/conftest.py",
150
+ "**/*egg-info*/",
151
+ "**/__pycache__/",
152
+ ".venv/",
153
+ ]
154
+ ignore_names = [
155
+ "main",
156
+ "*SignalCollector",
157
+ "*Collector",
158
+ "*ProcessingLoop",
159
+ "*Detector",
160
+ "*Registry",
161
+ "*Store",
162
+ "*Broker",
163
+ "*Catalog",
164
+ "*Spec",
165
+ "*Config",
166
+ "*Policy",
167
+ "*Manifest",
168
+ "*Error",
169
+ "*Exception",
170
+ "*Context",
171
+ "*Fragments",
172
+ "*Sections",
173
+ "*Evidence",
174
+ "*Summary",
175
+ "*Anomalies",
176
+ ]
177
+ ignore_decorators = ["@property"]
@@ -50,10 +50,13 @@ from __future__ import annotations
50
50
  import os
51
51
  import unicodedata
52
52
  from pathlib import Path
53
- from typing import Any
53
+ from typing import TYPE_CHECKING, Any
54
54
 
55
55
  from rich.console import Console
56
56
 
57
+ if TYPE_CHECKING:
58
+ from prompt_toolkit.key_binding import KeyBindings
59
+
57
60
  #: Unicode general categories that extend a grapheme cluster: combining
58
61
  #: marks, enclosing marks, format characters (variation selectors, ZWSP),
59
62
  #: and modifier symbols (skin-tone modifiers). ZWJ itself is ``Cf`` but is
@@ -186,7 +189,7 @@ def settings_file_path(data_dir: str | Path, profile: str) -> Path:
186
189
  """
187
190
  from runtime.config import profile_data_dir # lazy: import cost
188
191
 
189
- base = str(data_dir).strip() if str(data_dir).strip() else ""
192
+ base = str(data_dir).strip() or ""
190
193
  if not base and profile.strip():
191
194
  base = str(profile_data_dir(profile.strip()))
192
195
  if not base:
@@ -289,7 +292,7 @@ def prompt_history_path(data_dir: str | Path, profile: str) -> Path:
289
292
  the profile dir; empty hands the decision to the framework's default
290
293
  (``LISA_DATA_DIR`` > ``~/.lisa``).
291
294
  """
292
- base = str(data_dir).strip() if str(data_dir).strip() else ""
295
+ base = str(data_dir).strip() or ""
293
296
  if not base and profile.strip():
294
297
  from runtime.config import profile_data_dir # lazy: import cost
295
298
 
@@ -429,7 +432,7 @@ def _delete_first_grapheme(text: str) -> int:
429
432
  return i
430
433
 
431
434
 
432
- def _add_navigate_bindings(bindings: Any, *, swapped: bool = True) -> None:
435
+ def _add_navigate_bindings(bindings: KeyBindings, *, swapped: bool = True) -> None:
433
436
  """Bind submit/newline and navigation keys.
434
437
 
435
438
  ``swapped`` (the default) puts newline on Enter and send on
@@ -476,7 +479,7 @@ def _add_navigate_bindings(bindings: Any, *, swapped: bool = True) -> None:
476
479
  event.current_buffer.history_forward()
477
480
 
478
481
 
479
- def _add_grapheme_delete_bindings(bindings: Any) -> None:
482
+ def _add_grapheme_delete_bindings(bindings: KeyBindings) -> None:
480
483
  """Bind backspace (Ctrl-H) and forward Delete to cluster-aware cuts.
481
484
 
482
485
  prompt_toolkit deletes one codepoint, tearing multi-codepoint emoji
@@ -504,14 +507,17 @@ def _add_grapheme_delete_bindings(bindings: Any) -> None:
504
507
  buffer.cursor_position = pos
505
508
 
506
509
 
507
- def _tui_key_bindings(swapped: bool = True) -> Any:
510
+ def _tui_key_bindings(swapped: bool = True) -> KeyBindings:
508
511
  """Build the owned key model for the TUI reader.
509
512
 
510
513
  ``swapped`` selects the send/newline layout (see
511
514
  :func:`_add_navigate_bindings`); this exists so the reader body
512
515
  stays under its complexity budget.
513
516
  """
514
- bindings = _PT["KeyBindings"]()
517
+ pt = _PT
518
+ if pt is None: # pragma: no cover - guarded by the caller's _PT check
519
+ raise RuntimeError("_tui_key_bindings requires the prompt extra")
520
+ bindings: KeyBindings = pt["KeyBindings"]()
515
521
  _add_navigate_bindings(bindings, swapped=swapped)
516
522
  _add_grapheme_delete_bindings(bindings)
517
523
  return bindings