drydock-cli 3.0.85__tar.gz → 3.0.86__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 (103) hide show
  1. {drydock_cli-3.0.85/drydock_cli.egg-info → drydock_cli-3.0.86}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tui/app.py +20 -1
  3. {drydock_cli-3.0.85 → drydock_cli-3.0.86/drydock_cli.egg-info}/PKG-INFO +1 -1
  4. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/pyproject.toml +1 -1
  5. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_tui.py +26 -0
  6. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/LICENSE +0 -0
  7. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/NOTICE +0 -0
  8. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/README.md +0 -0
  9. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/__init__.py +0 -0
  10. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/__main__.py +0 -0
  11. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/advisor.py +0 -0
  12. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/agent.py +0 -0
  13. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/bash_safety.py +0 -0
  14. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/__init__.py +0 -0
  15. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/rmf-categorize.md +0 -0
  16. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/rmf-control.md +0 -0
  17. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/rmf-poam.md +0 -0
  18. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/rmf-review.md +0 -0
  19. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/stig-assess.md +0 -0
  20. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/builtin_skills/stig-remediate.md +0 -0
  21. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/cci.py +0 -0
  22. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/cli.py +0 -0
  23. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/compaction.py +0 -0
  24. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/config.py +0 -0
  25. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/detect.py +0 -0
  26. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/extract.py +0 -0
  27. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/gittools.py +0 -0
  28. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/graphrag.py +0 -0
  29. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/guards.py +0 -0
  30. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/loop_detect.py +0 -0
  31. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/mcp.py +0 -0
  32. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/poam.py +0 -0
  33. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/providers.py +0 -0
  34. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/rmf.py +0 -0
  35. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/rmf_graph.py +0 -0
  36. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/skills.py +0 -0
  37. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/stig.py +0 -0
  38. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tool_registry.py +0 -0
  39. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tools/__init__.py +0 -0
  40. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tui/__init__.py +0 -0
  41. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tui/approval.py +0 -0
  42. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tui/messages.py +0 -0
  43. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tui/widgets.py +0 -0
  44. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/tuning.py +0 -0
  45. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock/web.py +0 -0
  46. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock_cli.egg-info/SOURCES.txt +0 -0
  47. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock_cli.egg-info/dependency_links.txt +0 -0
  48. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock_cli.egg-info/entry_points.txt +0 -0
  49. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock_cli.egg-info/requires.txt +0 -0
  50. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/drydock_cli.egg-info/top_level.txt +0 -0
  51. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/setup.cfg +0 -0
  52. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_advisor.py +0 -0
  53. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_approval.py +0 -0
  54. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_back_command.py +0 -0
  55. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_bash_output_bounding.py +0 -0
  56. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_bash_process_group.py +0 -0
  57. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_bash_safety.py +0 -0
  58. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_bash_timeout_network.py +0 -0
  59. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_cci.py +0 -0
  60. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_cli_agents.py +0 -0
  61. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_compact_command.py +0 -0
  62. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_compaction.py +0 -0
  63. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_config.py +0 -0
  64. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_config_migration.py +0 -0
  65. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_context_limit_config.py +0 -0
  66. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_detect.py +0 -0
  67. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_dispatch.py +0 -0
  68. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_e2e_connected.py +0 -0
  69. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_empty_response.py +0 -0
  70. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_extract.py +0 -0
  71. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_failure_loop.py +0 -0
  72. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_first_run_setup.py +0 -0
  73. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_gittools.py +0 -0
  74. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_graphrag.py +0 -0
  75. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_guards_and_tools.py +0 -0
  76. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_hallucinated_tools.py +0 -0
  77. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_leaked_tool_call.py +0 -0
  78. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_loop_detect.py +0 -0
  79. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_mcp.py +0 -0
  80. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_oneshot_unreachable.py +0 -0
  81. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_plan_autocontinue.py +0 -0
  82. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_poam.py +0 -0
  83. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_providers_unreachable.py +0 -0
  84. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_read_index.py +0 -0
  85. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_rmf.py +0 -0
  86. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_rmf_graph.py +0 -0
  87. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_rmf_stig_graph.py +0 -0
  88. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_runaway_repetition.py +0 -0
  89. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_server_probe.py +0 -0
  90. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_skills.py +0 -0
  91. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_stig.py +0 -0
  92. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_stop.py +0 -0
  93. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_streaming_newlines.py +0 -0
  94. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_subagent.py +0 -0
  95. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_system_prompt_help.py +0 -0
  96. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_todo.py +0 -0
  97. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_tool_arg_parsing.py +0 -0
  98. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_tools_undo.py +0 -0
  99. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_tuning.py +0 -0
  100. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_viewimage.py +0 -0
  101. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_vision_input.py +0 -0
  102. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_web_tools.py +0 -0
  103. {drydock_cli-3.0.85 → drydock_cli-3.0.86}/tests/test_xccdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.85
3
+ Version: 3.0.86
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -59,6 +59,12 @@ BANNER = (
59
59
  # Animated "working" line: a turning-helm arc spinner + a nautical gerund +
60
60
  # elapsed time + streamed-token count. Rendered in-line above the status bar.
61
61
  _SPINNER = "◜◠◝◞◡◟"
62
+ # No agent event for this long → the activity line warns the model may be stalled
63
+ # (the gemma llama.cpp server can hang mid-generation on hard prompts). Advisory
64
+ # only. Set above the longest LEGIT silent stretch seen (a ~135s high-effort
65
+ # think before the first tool call) so normal slow turns don't nag; observed
66
+ # stalls ran 3–5 min+, so 180s still flags them well before the 30-min timeout.
67
+ _STALL_HINT_SECS = 180
62
68
  _WORKING_WORDS = [
63
69
  "Battening", "Splicing", "Hoisting", "Heaving", "Trimming", "Tacking",
64
70
  "Mooring", "Charting", "Navigating", "Sounding", "Caulking", "Rigging",
@@ -262,6 +268,7 @@ class DrydockApp(App):
262
268
  self._work_start = 0.0
263
269
  self._work_word = ""
264
270
  self._work_chars = 0 # streamed output chars this turn (→ ~tokens)
271
+ self._last_progress = 0.0 # monotonic time of the last agent event (stall watchdog)
265
272
  self._spinner_i = 0
266
273
 
267
274
  # The agent (worker thread) calls this to gate a sensitive command on
@@ -349,7 +356,13 @@ class DrydockApp(App):
349
356
  effort = self.state.current_effort
350
357
  eff = f" · thinking with {effort} effort" if effort else ""
351
358
  queued = f" · {len(self._queue)} queued" if self._queue else ""
352
- return f"{spin} {self._work_word}… ({elapsed} · {toks} tokens{eff}{queued})"
359
+ # Stall watchdog (advisory): if no agent event has arrived for a while,
360
+ # the model server may be hung. Flag it so the user isn't left guessing
361
+ # whether it's thinking or stalled — but never act (Esc is theirs).
362
+ silent = time.monotonic() - self._last_progress if self._last_progress else 0.0
363
+ stall = (f" ⚠ no output for {int(silent)}s — the model may be slow or stalled; "
364
+ "Esc to stop") if silent > _STALL_HINT_SECS else ""
365
+ return f"{spin} {self._work_word}… ({elapsed} · ↓ {toks} tokens{eff}{queued}){stall}"
353
366
 
354
367
  def _refresh_status(self) -> None:
355
368
  # The 0.18s _tick_work timer can fire one last time DURING app teardown,
@@ -435,6 +448,7 @@ class DrydockApp(App):
435
448
  self.query_one("#todo", Static).update("")
436
449
  self._busy = True
437
450
  self._work_start = time.monotonic()
451
+ self._last_progress = self._work_start
438
452
  self._work_word = random.choice(_WORKING_WORDS)
439
453
  self._work_chars = 0
440
454
  self._spinner_i = 0
@@ -1133,6 +1147,11 @@ class DrydockApp(App):
1133
1147
  def _run_agent(self, text: str) -> None:
1134
1148
  try:
1135
1149
  for ev in run(text, self.state, self.config, self.system):
1150
+ # Any event = the model/server is making progress → reset the
1151
+ # stall watchdog. During a real stall the provider stream blocks
1152
+ # and NO event arrives, so this timestamp freezes and
1153
+ # _working_text surfaces a hint.
1154
+ self._last_progress = time.monotonic()
1136
1155
  if isinstance(ev, ReasoningChunk):
1137
1156
  self.post_message(AgentReasoning(ev.text))
1138
1157
  elif isinstance(ev, TextChunk):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.85
3
+ Version: 3.0.86
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.0.85"
10
+ version = "3.0.86"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -457,3 +457,29 @@ def test_ask_bang_injects_advice_but_plain_ask_does_not():
457
457
  assert started == []
458
458
 
459
459
  asyncio.run(main())
460
+
461
+
462
+ def test_stall_watchdog_hint_appears_after_silence():
463
+ """The activity line warns when no agent event has arrived for a while
464
+ (a hung model server) — advisory, and it clears once progress resumes."""
465
+ import time as _time
466
+ from drydock.tui.app import _STALL_HINT_SECS
467
+
468
+ async def main():
469
+ app = DrydockApp({"model": "gemma4", "provider": "vllm", "cwd": "/tmp"})
470
+ async with app.run_test() as pilot:
471
+ await pilot.pause()
472
+ app._busy = True
473
+ app._work_start = _time.monotonic()
474
+ app._work_word = "Working"
475
+ # fresh progress → no hint
476
+ app._last_progress = _time.monotonic()
477
+ assert "stalled" not in app._working_text()
478
+ # simulate silence beyond the threshold → hint appears
479
+ app._last_progress = _time.monotonic() - (_STALL_HINT_SECS + 5)
480
+ assert "stalled" in app._working_text() and "Esc to stop" in app._working_text()
481
+ # progress resumes → hint clears
482
+ app._last_progress = _time.monotonic()
483
+ assert "stalled" not in app._working_text()
484
+
485
+ asyncio.run(main())
File without changes
File without changes
File without changes
File without changes