More progressbar updates. Removed Claud specific progress bar detection, hopefully caught now by generic progress bar updates. They do change it all the time, so it may work, but shouldn't be expected to do so.
This commit is contained in:
@@ -653,6 +653,10 @@ Building...
|
|||||||
- **Non-blocking**: Progress tones don't interrupt speech or other functionality
|
- **Non-blocking**: Progress tones don't interrupt speech or other functionality
|
||||||
- **Configurable**: Can be enabled/disabled as needed
|
- **Configurable**: Can be enabled/disabled as needed
|
||||||
|
|
||||||
|
Fenrir detects stable progress structures rather than application-specific
|
||||||
|
status formats. Application-specific formats change too frequently to support
|
||||||
|
reliably.
|
||||||
|
|
||||||
### Usage Examples
|
### Usage Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -312,6 +312,9 @@ Fenrir automatically detects and provides audio feedback for progress indicators
|
|||||||
- **Automatic**: Works with downloads, compilations, installations
|
- **Automatic**: Works with downloads, compilations, installations
|
||||||
- **Remote control**: Enable via socket commands
|
- **Remote control**: Enable via socket commands
|
||||||
|
|
||||||
|
Fenrir detects stable progress structures rather than application-specific
|
||||||
|
status formats, which change too frequently to support reliably.
|
||||||
|
|
||||||
### Spell Checking
|
### Spell Checking
|
||||||
- `Fenrir + S` - Spell check current word
|
- `Fenrir + S` - Spell check current word
|
||||||
- `Fenrir + S S` - Add word to dictionary
|
- `Fenrir + S S` - Add word to dictionary
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class command:
|
|||||||
delta_length = len(delta_text)
|
delta_length = len(delta_text)
|
||||||
if (
|
if (
|
||||||
delta_length > 200
|
delta_length > 200
|
||||||
): # Allow longer progress lines like Claude Code's status
|
): # Allow longer progress lines such as terminal status output
|
||||||
if not self.is_explicit_progress_delta(delta_text):
|
if not self.is_explicit_progress_delta(delta_text):
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
f"Progress filter: delta too long ({delta_length})",
|
f"Progress filter: delta too long ({delta_length})",
|
||||||
@@ -326,43 +326,27 @@ class command:
|
|||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||||
return
|
return
|
||||||
|
|
||||||
# Pattern 6: Claude Code working indicators (various symbols + activity text + "esc/ctrl+c to interrupt")
|
# Pattern 6: Interruptible terminal activity indicators
|
||||||
# Matches any: [symbol] [Task description]… (... to interrupt ...)
|
# Matches any: [symbol] [Task description][…] (... to interrupt ...)
|
||||||
# Symbols include: * ✢ ✽ ✶ ✻ · • ◦ ○ ● ◆ and similar decorative characters
|
# Symbols include: * ✢ ✽ ✶ ✻ · • ◦ ○ ● ◆ and similar decorative characters
|
||||||
# Example: ✽ Reviewing script for issues… (ctrl+c to interrupt · 33s · ↑ 1.6k tokens · thought for 4s)
|
# Keep this structural rather than adding application-specific formats,
|
||||||
claude_progress_match = re.search(
|
# which change too frequently to support reliably.
|
||||||
r'[*✢✽✶✻·•◦○●◆]\s+\w+.*?…\s*\(.*(?:esc|ctrl\+c) to interrupt.*\)',
|
interruptible_activity_match = re.search(
|
||||||
|
r'[*✢✽✶✻·•◦○●◆]\s+\w+.*?(?:…\s*)?\(.*(?:esc|ctrl\+c) to interrupt.*\)',
|
||||||
text,
|
text,
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
if claude_progress_match:
|
if interruptible_activity_match:
|
||||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||||
"Playing Claude Code activity beep",
|
"Playing interruptible activity beep",
|
||||||
debug.DebugLevel.INFO,
|
debug.DebugLevel.INFO,
|
||||||
)
|
)
|
||||||
self.play_activity_beep()
|
self.play_activity_beep()
|
||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
||||||
return
|
return
|
||||||
|
|
||||||
# Pattern 6b: Claude Code tool invocation indicators (● Tool Name(...))
|
# Pattern 6b: Bullet/white bullet activity lines (•/◦ ...)
|
||||||
# Example: ● Web Search("query here")
|
|
||||||
tool_invocation_match = re.search(
|
|
||||||
r'[●○◉•◦]\s+(?:Web\s*Search|Read|Write|Edit|Bash|Glob|Grep|Task|WebFetch)\s*\(',
|
|
||||||
text,
|
|
||||||
re.IGNORECASE,
|
|
||||||
)
|
|
||||||
if tool_invocation_match:
|
|
||||||
if current_time - self.env["commandBuffer"]["lastProgressTime"] >= 1.0:
|
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
|
||||||
"Playing Claude Code tool invocation beep",
|
|
||||||
debug.DebugLevel.INFO,
|
|
||||||
)
|
|
||||||
self.play_activity_beep()
|
|
||||||
self.env["commandBuffer"]["lastProgressTime"] = current_time
|
|
||||||
return
|
|
||||||
|
|
||||||
# Pattern 6c: Bullet/white bullet activity lines (•/◦ ...)
|
|
||||||
bullet_activity_match = re.search(
|
bullet_activity_match = re.search(
|
||||||
(
|
(
|
||||||
r'^\s*[•◦]\s+.*(?:…|\.{3,}|\b(?:thinking|working|processing|'
|
r'^\s*[•◦]\s+.*(?:…|\.{3,}|\b(?:thinking|working|processing|'
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributors.
|
# By Chrys, Storm Dragon, and contributors.
|
||||||
|
|
||||||
version = "2026.05.31"
|
version = "2026.06.01"
|
||||||
code_name = "master"
|
code_name = "master"
|
||||||
|
|||||||
@@ -109,3 +109,34 @@ def test_progress_detector_beeps_for_long_tqdm_transfer_delta():
|
|||||||
|
|
||||||
command.play_progress_tone.assert_called_once_with(90.0)
|
command.play_progress_tone.assert_called_once_with(90.0)
|
||||||
assert command.env["commandBuffer"]["lastProgressValue"] == 90.0
|
assert command.env["commandBuffer"]["lastProgressValue"] == 90.0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_progress_detector_beeps_for_interruptible_status_without_ellipsis():
|
||||||
|
progress_module = _load_progress_module()
|
||||||
|
command = progress_module.command()
|
||||||
|
sample = "◦ Files: (1m 04s • esc to interrupt)"
|
||||||
|
command.env = {
|
||||||
|
"commandBuffer": {
|
||||||
|
"progress_monitoring": True,
|
||||||
|
"lastProgressValue": -1,
|
||||||
|
"lastProgressTime": 0,
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"DebugManager": Mock(write_debug_out=Mock()),
|
||||||
|
"ScreenManager": Mock(is_screen_change=Mock(return_value=False)),
|
||||||
|
"CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)),
|
||||||
|
},
|
||||||
|
"screen": {
|
||||||
|
"new_delta": sample,
|
||||||
|
"new_delta_is_typing": False,
|
||||||
|
"new_content_text": sample,
|
||||||
|
"old_cursor": {"x": 0, "y": 0},
|
||||||
|
"new_cursor": {"x": 0, "y": 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
command.play_activity_beep = Mock()
|
||||||
|
|
||||||
|
command.run()
|
||||||
|
|
||||||
|
command.play_activity_beep.assert_called_once_with()
|
||||||
|
|||||||
Reference in New Issue
Block a user