langstage-cli 0.6.45__tar.gz → 0.6.46__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 (73) hide show
  1. {langstage_cli-0.6.45/langstage_cli.egg-info → langstage_cli-0.6.46}/PKG-INFO +1 -1
  2. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/cli.py +20 -3
  3. {langstage_cli-0.6.45 → langstage_cli-0.6.46/langstage_cli.egg-info}/PKG-INFO +1 -1
  4. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli.egg-info/SOURCES.txt +1 -0
  5. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/pyproject.toml +1 -1
  6. langstage_cli-0.6.46/tests/test_usage_hint_186.py +52 -0
  7. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/LICENSE +0 -0
  8. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/README.md +0 -0
  9. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/deepagent_code/__init__.py +0 -0
  10. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/__init__.py +0 -0
  11. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/agui_stream.py +0 -0
  12. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/config.py +0 -0
  13. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/exit_codes.py +0 -0
  14. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli/sessions.py +0 -0
  15. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli.egg-info/dependency_links.txt +0 -0
  16. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli.egg-info/entry_points.txt +0 -0
  17. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli.egg-info/requires.txt +0 -0
  18. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/langstage_cli.egg-info/top_level.txt +0 -0
  19. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/setup.cfg +0 -0
  20. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_advertised_wave4.py +0 -0
  21. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_agui_stream.py +0 -0
  22. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_approval_menu_abort.py +0 -0
  23. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_async_mode.py +0 -0
  24. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_checkpointer.py +0 -0
  25. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_cli.py +0 -0
  26. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_cli_help.py +0 -0
  27. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_codeconfig.py +0 -0
  28. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_config.py +0 -0
  29. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_config_command.py +0 -0
  30. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_configurable.py +0 -0
  31. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_deferred_pass.py +0 -0
  32. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_dumb_term.py +0 -0
  33. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_exit_codes.py +0 -0
  34. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_generic_interrupt.py +0 -0
  35. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_help_render.py +0 -0
  36. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_history_persist.py +0 -0
  37. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_hitl_approval_preview.py +0 -0
  38. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_hitl_resume_warning.py +0 -0
  39. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_init.py +0 -0
  40. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_interrupt_non_tty.py +0 -0
  41. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_legacy_config_home.py +0 -0
  42. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_load_error.py +0 -0
  43. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_message_boundaries.py +0 -0
  44. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_no_color.py +0 -0
  45. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_no_interactive_approve.py +0 -0
  46. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_no_persist_resume.py +0 -0
  47. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_persist_env.py +0 -0
  48. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_quiet_output.py +0 -0
  49. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_reasoning_render.py +0 -0
  50. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_rename_shim.py +0 -0
  51. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_render_markdown.py +0 -0
  52. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_session_lifecycle.py +0 -0
  53. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_sessions.py +0 -0
  54. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_show_config.py +0 -0
  55. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_show_config_malformed.py +0 -0
  56. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_spec_loading_core.py +0 -0
  57. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_spec_resolution.py +0 -0
  58. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_spinner_reply_survives.py +0 -0
  59. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_stdin_interactive.py +0 -0
  60. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_stdin_single_shot.py +0 -0
  61. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_stream_mode.py +0 -0
  62. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_streaming_marker.py +0 -0
  63. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_terminal_width.py +0 -0
  64. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_toml_relative_paths.py +0 -0
  65. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_tool_card_args.py +0 -0
  66. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_tool_output_escape.py +0 -0
  67. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_turn_error_verbose.py +0 -0
  68. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_turn_exit_and_render.py +0 -0
  69. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_unicode_console.py +0 -0
  70. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_verbose_command.py +0 -0
  71. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_verify_flag.py +0 -0
  72. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_workspace.py +0 -0
  73. {langstage_cli-0.6.45 → langstage_cli-0.6.46}/tests/test_wrong_type_graph.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langstage-cli
3
- Version: 0.6.45
3
+ Version: 0.6.46
4
4
  Summary: The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph
5
5
  Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
6
6
  License-Expression: MIT
@@ -1001,6 +1001,15 @@ def _default_agent_path() -> Optional[Path]:
1001
1001
  return path if path.exists() else None
1002
1002
 
1003
1003
 
1004
+ # A MESSAGE that is really an agent spec: ``my_agent.py:graph`` or ``pkg.module:agent``.
1005
+ _SPEC_LIKE = re.compile(r"^(?:(?:[A-Za-z]:)?[^\s:]+\.py|[A-Za-z_][\w.]*):[A-Za-z_]\w*$")
1006
+
1007
+
1008
+ def _looks_like_agent_spec(message: Optional[str]) -> bool:
1009
+ """Whether a positional MESSAGE looks like an agent spec meant for ``-a`` (gh #186)."""
1010
+ return bool(message) and bool(_SPEC_LIKE.match(message.strip()))
1011
+
1012
+
1004
1013
  def _no_agent_toml_hint(cfg: Any, toml_sources: list) -> List[str]:
1005
1014
  """Lines explaining why a ``langstage.toml`` that was read supplied no spec (gh #148).
1006
1015
 
@@ -3468,10 +3477,18 @@ def main(
3468
3477
  # of only pointing at the env var (gh #148).
3469
3478
  for line in _no_agent_toml_hint(cfg, toml_sources):
3470
3479
  _status(f"{YELLOW}{line}{RESET}")
3480
+ # The spec went in as the MESSAGE: name the command that works (gh #186).
3481
+ if _looks_like_agent_spec(message):
3482
+ _status(
3483
+ f"{YELLOW}The agent spec goes after -a: langstage-cli -a {message.strip()}{RESET}"
3484
+ )
3471
3485
  _status(f"\n{DIM}Usage:{RESET}")
3472
- _status(" langstage-cli path/to/agent.py:graph")
3473
- _status(" langstage-cli mypackage.module:agent")
3474
- _status(f"\n{DIM}Or set the LANGSTAGE_AGENT_SPEC environment variable{RESET}")
3486
+ _status(" langstage-cli -a path/to/agent.py:graph")
3487
+ _status(" langstage-cli -a mypackage.module:agent")
3488
+ _status(
3489
+ f"\n{DIM}Or set LANGSTAGE_AGENT_SPEC, put the spec under [agent] spec in "
3490
+ f"langstage.toml, or run `langstage-cli init` for a starter agent{RESET}"
3491
+ )
3475
3492
  sys.exit(1)
3476
3493
 
3477
3494
  # The BASE directory a relative spec resolves against depends on WHERE it came
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langstage-cli
3
- Version: 0.6.45
3
+ Version: 0.6.46
4
4
  Summary: The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph
5
5
  Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
6
6
  License-Expression: MIT
@@ -64,6 +64,7 @@ tests/test_tool_output_escape.py
64
64
  tests/test_turn_error_verbose.py
65
65
  tests/test_turn_exit_and_render.py
66
66
  tests/test_unicode_console.py
67
+ tests/test_usage_hint_186.py
67
68
  tests/test_verbose_command.py
68
69
  tests/test_verify_flag.py
69
70
  tests/test_workspace.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "langstage-cli"
7
- version = "0.6.45"
7
+ version = "0.6.46"
8
8
  description = "The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,52 @@
1
+ """gh #186: the "No agent specified" hint shows commands that work (with -a)."""
2
+
3
+ import pytest
4
+ from click.testing import CliRunner
5
+
6
+ from langstage_cli import cli
7
+ from langstage_cli.cli import _looks_like_agent_spec, main
8
+
9
+
10
+ @pytest.fixture
11
+ def no_agent(tmp_path, monkeypatch):
12
+ monkeypatch.chdir(tmp_path)
13
+ for var in ("LANGSTAGE_AGENT_SPEC", "DEEPAGENT_AGENT_SPEC", "DEEPAGENT_SPEC"):
14
+ monkeypatch.delenv(var, raising=False)
15
+ monkeypatch.setattr(cli, "_default_agent_path", lambda: None)
16
+
17
+
18
+ def test_usage_hint_uses_dash_a(no_agent):
19
+ r = CliRunner().invoke(main, ["hi"])
20
+ assert r.exit_code == 1, r.output
21
+ assert "No agent specified" in r.output
22
+ assert "langstage-cli -a path/to/agent.py:graph" in r.output
23
+ assert "langstage-cli -a mypackage.module:agent" in r.output
24
+ assert "[agent] spec" in r.output and "langstage-cli init" in r.output
25
+ # Not a spec-looking message: no "goes after -a" line.
26
+ assert "goes after -a" not in r.output
27
+
28
+
29
+ @pytest.mark.parametrize("spec", ["my_agent.py:graph", "mypackage.module:agent"])
30
+ def test_spec_passed_as_message_names_the_working_command(no_agent, spec):
31
+ r = CliRunner().invoke(main, [spec])
32
+ assert r.exit_code == 1, r.output
33
+ assert f"The agent spec goes after -a: langstage-cli -a {spec}" in r.output
34
+
35
+
36
+ @pytest.mark.parametrize(
37
+ "message,expected",
38
+ [
39
+ ("my_agent.py:graph", True),
40
+ ("./agents/a.py:graph", True),
41
+ (r"C:\work\agent.py:graph", True),
42
+ ("pkg.module:agent", True),
43
+ ("hello", False),
44
+ ("what is 2:3", False),
45
+ ("ratio 3:1 please", False),
46
+ ("http://example.org:80", False),
47
+ ("", False),
48
+ (None, False),
49
+ ],
50
+ )
51
+ def test_looks_like_agent_spec(message, expected):
52
+ assert _looks_like_agent_spec(message) is expected
File without changes
File without changes
File without changes