feat: Enhance local command handling and introduce local intents

- Refactor `run_local_command` to manage subprocesses more effectively, ensuring child processes are terminated on timeout.
- Introduce `_terminate` function to handle process group termination and capture output.
- Implement `_command_output` to format command results with a character limit.
- Add local intent recognition in `intents.py` to handle commands like "stop", "go to sleep", and "come here" without server interaction.
- Normalize user input to match local intents while stripping filler words.
- Update tests to cover new local intent functionality and ensure proper command handling.
- Enhance speech processing to handle abbreviations and improve spoken output clarity.
This commit is contained in:
2026-08-05 18:31:02 -06:00
parent 8d4751d80f
commit 3ee67cb4d6
14 changed files with 1107 additions and 59 deletions
+26
View File
@@ -78,3 +78,29 @@ def test_is_question_ignores_question_marks_that_are_not_spoken():
assert not is_question("Docs are at https://example.com/x?y=1")
assert not is_question("")
assert not is_question(None)
def test_abbreviations_are_worded_instead_of_spelled_out():
"""The periods make these look like sentence boundaries, so the voice reads
them letter by letter ("eee gee")."""
assert for_speech("Use a flag, e.g. --force") == "Use a flag, for example force"
assert for_speech("i.e. the config file") == "that is the config file"
assert for_speech("logs, configs, etc.") == "logs, configs, and so on"
assert for_speech("docker vs. podman") == "docker versus podman"
assert for_speech("Fixed in PR #42") == "Fixed in PR number 42"
def test_abbreviation_wording_is_word_bounded():
""""vs" inside a word or filename isn't an abbreviation."""
assert "versus" not in for_speech("the vscode window")
assert "versus" not in for_speech("revs per minute")
# A markdown heading has no digit after the hashes, so it's still a heading.
assert for_speech("## Results") == "Results"
def test_long_option_dashes_are_dropped_but_hyphens_survive():
assert for_speech("run it with --force") == "run it with force"
assert for_speech("check bolt-pet is up-to-date") == "check bolt-pet is up-to-date"
# The rule line is gone; the full stops are _bullets_to_sentences giving the
# voice a pause where the eye saw a line break.
assert for_speech("one\n---\ntwo") == "one. two."