Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f18c31df6c | |||
| ca0e3b5987 | |||
| 0009d90a68 | |||
| 2c2efc56f0 | |||
| 3dca3e5b23 | |||
| 27c35939b1 | |||
| 7e87ebf04b | |||
| ec6c135581 | |||
| 998c63cc71 | |||
| 1b9a9a90b1 | |||
| 4c8c8d896d | |||
| 4672592dba | |||
| 7a12992b88 | |||
| 7a87fb51bb | |||
| 2cc2fda28c | |||
| c99d0f6ee1 | |||
| 5b642cd9e2 |
@@ -6,3 +6,4 @@ dist/
|
|||||||
build/
|
build/
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
.directory
|
.directory
|
||||||
|
CLAUDE.md
|
||||||
|
|||||||
@@ -75,9 +75,10 @@ KEY_FENRIR,KEY_F2=toggle_braille
|
|||||||
KEY_FENRIR,KEY_F3=toggle_sound
|
KEY_FENRIR,KEY_F3=toggle_sound
|
||||||
KEY_FENRIR,KEY_F4=toggle_speech
|
KEY_FENRIR,KEY_F4=toggle_speech
|
||||||
KEY_FENRIR,KEY_ENTER=temp_disable_speech
|
KEY_FENRIR,KEY_ENTER=temp_disable_speech
|
||||||
|
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=silence_until_prompt
|
||||||
KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
|
KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
|
||||||
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
|
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
|
||||||
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=toggle_output
|
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output
|
||||||
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
|
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
|
||||||
KEY_FENRIR,KEY_ENTER=toggle_auto_read
|
KEY_FENRIR,KEY_ENTER=toggle_auto_read
|
||||||
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
|
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
|
|||||||
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
||||||
|
|
||||||
# Enable progress bar monitoring with ascending tones by default
|
# Enable progress bar monitoring with ascending tones by default
|
||||||
progressMonitoring=False
|
progressMonitoring=True
|
||||||
|
|
||||||
[speech]
|
[speech]
|
||||||
# Turn speech on or off:
|
# Turn speech on or off:
|
||||||
@@ -166,7 +166,7 @@ autoPresentIndent=False
|
|||||||
# 1 = sound only
|
# 1 = sound only
|
||||||
# 2 = speak only
|
# 2 = speak only
|
||||||
autoPresentIndentMode=1
|
autoPresentIndentMode=1
|
||||||
# play a sound when attributes are changeing
|
# play a sound when attributes change
|
||||||
hasAttributes=True
|
hasAttributes=True
|
||||||
# shell for PTY emulatiun (empty = default shell)
|
# shell for PTY emulatiun (empty = default shell)
|
||||||
shell=
|
shell=
|
||||||
@@ -220,7 +220,7 @@ quickMenu=speech#rate;speech#pitch;speech#volume
|
|||||||
# Each pattern should be on a separate line, format: customPatterns=pattern1,pattern2,pattern3
|
# Each pattern should be on a separate line, format: customPatterns=pattern1,pattern2,pattern3
|
||||||
# Examples:
|
# Examples:
|
||||||
# For PS1='[\u@\h \W] \$ ' use: \[.*@.*\s.*\]\s*[$#>]\s*
|
# For PS1='[\u@\h \W] \$ ' use: \[.*@.*\s.*\]\s*[$#>]\s*
|
||||||
# For "[storm@fenrir ~] $" use: \[.*@.*\s.*\]\s*[$#>]\s*
|
# For "[user@hostname ~] $" use: \[.*@.*\s.*\]\s*[$#>]\s*
|
||||||
# For custom prompts ending with specific strings, use patterns like: .*your_prompt_ending$
|
# For custom prompts ending with specific strings, use patterns like: .*your_prompt_ending$
|
||||||
customPatterns=
|
customPatterns=
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ customPatterns=
|
|||||||
exactMatches=
|
exactMatches=
|
||||||
|
|
||||||
[time]
|
[time]
|
||||||
# automatic time anouncement
|
# automatic time announcement
|
||||||
enabled=False
|
enabled=False
|
||||||
# present time
|
# present time
|
||||||
presentTime=True
|
presentTime=True
|
||||||
|
|||||||
@@ -60,29 +60,34 @@ class command():
|
|||||||
# Debug: Print what we're checking
|
# Debug: Print what we're checking
|
||||||
self.env['runtime']['debug'].writeDebugOut("Progress detector checking: '" + text + "'", debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Progress detector checking: '" + text + "'", debug.debugLevel.INFO)
|
||||||
|
|
||||||
# Check if progress monitoring should automatically stop
|
# Note: Auto-disable on 100% completion removed to respect user settings
|
||||||
self.checkProgressCompletion(text, currentTime)
|
|
||||||
|
|
||||||
# Pattern 1: Percentage (50%, 25.5%, etc.)
|
# Pattern 1: Percentage (50%, 25.5%, etc.)
|
||||||
percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text)
|
percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text)
|
||||||
if percentMatch:
|
if percentMatch:
|
||||||
percentage = float(percentMatch.group(1))
|
percentage = float(percentMatch.group(1))
|
||||||
self.env['runtime']['debug'].writeDebugOut("Found percentage: " + str(percentage), debug.debugLevel.INFO)
|
# Only trigger on realistic progress percentages (0-100%)
|
||||||
if percentage != self.env['commandBuffer']['lastProgressValue']:
|
if 0 <= percentage <= 100:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Playing tone for: " + str(percentage), debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Found percentage: " + str(percentage), debug.debugLevel.INFO)
|
||||||
self.playProgressTone(percentage)
|
if percentage != self.env['commandBuffer']['lastProgressValue']:
|
||||||
self.env['commandBuffer']['lastProgressValue'] = percentage
|
self.env['runtime']['debug'].writeDebugOut("Playing tone for: " + str(percentage), debug.debugLevel.INFO)
|
||||||
self.env['commandBuffer']['lastProgressTime'] = currentTime
|
self.playProgressTone(percentage)
|
||||||
return
|
self.env['commandBuffer']['lastProgressValue'] = percentage
|
||||||
|
self.env['commandBuffer']['lastProgressTime'] = currentTime
|
||||||
|
return
|
||||||
|
|
||||||
# Pattern 1b: Time/token activity (not percentage-based, so use single beep)
|
# Pattern 1b: Time/token activity (not percentage-based, so use single beep)
|
||||||
timeMatch = re.search(r'(\d+)s\s', text)
|
timeMatch = re.search(r'(\d+)s\s', text)
|
||||||
tokenMatch = re.search(r'(\d+)\s+tokens', text)
|
tokenMatch = re.search(r'(\d+)\s+tokens', text)
|
||||||
|
# Pattern 1c: dd command output (bytes copied with transfer rate)
|
||||||
|
ddMatch = re.search(r'\d+\s+bytes.*copied.*\d+\s+s.*[kMGT]?B/s', text)
|
||||||
|
# Pattern 1d: Curl-style transfer data (bytes, speed indicators)
|
||||||
|
curlMatch = re.search(r'(\d+\s+\d+\s+\d+\s+\d+.*?(?:k|M|G)?.*?--:--:--|Speed)', text)
|
||||||
|
|
||||||
if timeMatch or tokenMatch:
|
if timeMatch or tokenMatch or ddMatch or curlMatch:
|
||||||
# For non-percentage progress, use a single activity beep every 2 seconds
|
# For non-percentage progress, use a single activity beep every 2 seconds
|
||||||
if currentTime - self.env['commandBuffer']['lastProgressTime'] >= 2.0:
|
if currentTime - self.env['commandBuffer']['lastProgressTime'] >= 2.0:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Playing activity beep for Claude Code progress", debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Playing activity beep for transfer progress", debug.debugLevel.INFO)
|
||||||
self.playActivityBeep()
|
self.playActivityBeep()
|
||||||
self.env['commandBuffer']['lastProgressTime'] = currentTime
|
self.env['commandBuffer']['lastProgressTime'] = currentTime
|
||||||
return
|
return
|
||||||
@@ -148,21 +153,6 @@ class command():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Sox tone error: " + str(e), debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Sox tone error: " + str(e), debug.debugLevel.ERROR)
|
||||||
|
|
||||||
def checkProgressCompletion(self, text, currentTime):
|
|
||||||
"""Check if progress is complete and should auto-disable monitoring"""
|
|
||||||
# Progress monitor is now beep-only - user controls speech separately
|
|
||||||
# Only auto-disable on clear 100% completion for convenience
|
|
||||||
import re
|
|
||||||
|
|
||||||
if re.search(r'100\s*%', text):
|
|
||||||
self.env['runtime']['debug'].writeDebugOut("Progress complete: 100%", debug.debugLevel.INFO)
|
|
||||||
self.stopProgressMonitoring()
|
|
||||||
return
|
|
||||||
|
|
||||||
def stopProgressMonitoring(self):
|
|
||||||
"""Stop progress monitoring - beep-only, no speech control"""
|
|
||||||
self.env['commandBuffer']['progressMonitoring'] = False
|
|
||||||
# Just disable monitoring, don't touch speech settings
|
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
pass
|
pass
|
||||||
@@ -38,7 +38,7 @@ class textManager():
|
|||||||
if name[0] == name[1]:
|
if name[0] == name[1]:
|
||||||
newText += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' '
|
newText += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' '
|
||||||
else:
|
else:
|
||||||
newText += ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name, True) + ' '
|
newText += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' '
|
||||||
lastPos = span[1]
|
lastPos = span[1]
|
||||||
if lastPos != 0:
|
if lastPos != 0:
|
||||||
newText += ' '
|
newText += ' '
|
||||||
@@ -46,7 +46,7 @@ class textManager():
|
|||||||
lastPos = 0
|
lastPos = 0
|
||||||
for match in self.regExSingle.finditer(newText):
|
for match in self.regExSingle.finditer(newText):
|
||||||
span = match.span()
|
span = match.span()
|
||||||
result += text[lastPos:span[0]]
|
result += newText[lastPos:span[0]]
|
||||||
numberOfChars = len(newText[span[0]:span[1]])
|
numberOfChars = len(newText[span[0]:span[1]])
|
||||||
name = newText[span[0]:span[1]][:2]
|
name = newText[span[0]:span[1]][:2]
|
||||||
if not self.env['runtime']['punctuationManager'].isPuctuation(name[0]):
|
if not self.env['runtime']['punctuationManager'].isPuctuation(name[0]):
|
||||||
@@ -55,7 +55,7 @@ class textManager():
|
|||||||
if name[0] == name[1]:
|
if name[0] == name[1]:
|
||||||
result += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' '
|
result += ' ' + str(numberOfChars) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' '
|
||||||
else:
|
else:
|
||||||
result += ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name, True) + ' '
|
result += ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[0], True) + ' ' + str(int(numberOfChars / 2)) + ' ' + self.env['runtime']['punctuationManager'].proceedPunctuation(name[1], True) + ' '
|
||||||
lastPos = span[1]
|
lastPos = span[1]
|
||||||
if lastPos != 0:
|
if lastPos != 0:
|
||||||
result += ' '
|
result += ' '
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
# By Chrys, Storm Dragon, and contributers.
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
version = "2025.06.07"
|
version = "2025.06.07"
|
||||||
codeName = "testing"
|
codeName = "master"
|
||||||
|
|||||||
@@ -45,28 +45,17 @@ class driver(remoteDriver):
|
|||||||
continue
|
continue
|
||||||
if self.fenrirSock in r:
|
if self.fenrirSock in r:
|
||||||
client_sock, client_addr = self.fenrirSock.accept()
|
client_sock, client_addr = self.fenrirSock.accept()
|
||||||
response = "ERROR: Failed to process command\n"
|
|
||||||
try:
|
try:
|
||||||
rawdata = client_sock.recv(8129)
|
rawdata = client_sock.recv(8129)
|
||||||
data = rawdata.decode("utf-8").rstrip().lstrip()
|
|
||||||
if data:
|
|
||||||
# Process the command and get response
|
|
||||||
result = self.env['runtime']['remoteManager'].handleRemoteIncommingWithResponse(data)
|
|
||||||
if result['success']:
|
|
||||||
response = f"OK: {result['message']}\n"
|
|
||||||
else:
|
|
||||||
response = f"ERROR: {result['message']}\n"
|
|
||||||
else:
|
|
||||||
response = "ERROR: Empty command\n"
|
|
||||||
except Exception as e:
|
|
||||||
response = f"ERROR: {str(e)}\n"
|
|
||||||
|
|
||||||
# Send response back to client
|
|
||||||
try:
|
|
||||||
client_sock.send(response.encode("utf-8"))
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
|
data = rawdata.decode("utf-8").rstrip().lstrip()
|
||||||
|
eventQueue.put({"Type":fenrirEventType.RemoteIncomming,
|
||||||
|
"Data": data
|
||||||
|
})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
client_sock.close()
|
client_sock.close()
|
||||||
except:
|
except:
|
||||||
|
|||||||
Reference in New Issue
Block a user