Skip to content

feat: delegate tab completion to PTY bash#146

Merged
F16shen merged 3 commits into
AI-Shell-Team:mainfrom
jexShain:feat/pty-bash-completion
May 7, 2026
Merged

feat: delegate tab completion to PTY bash#146
F16shen merged 3 commits into
AI-Shell-Team:mainfrom
jexShain:feat/pty-bash-completion

Conversation

@jexShain
Copy link
Copy Markdown
Collaborator

@jexShain jexShain commented Apr 30, 2026

Summary

  • Replace custom Python completion system (PATH scanning + PathCompleter) with PTY bash delegation
  • Add __aish_query_completions and __aish_mark_dirs functions to bash_rc_wrapper.sh, leveraging compgen and bash-completion functions for context-aware completions
  • Support full bash-completion: git add <tab>, systemctl <tab>, etc.
  • Graceful fallback to original PATH scanning when PTY is unavailable or query times out (500ms)

Test plan

  • git <tab> shows git subcommands
  • systemctl <tab> shows systemctl subcommands
  • ls /tmp/<tab> shows file/directory completions
  • /mod<tab> completes to /model (special aish commands still work)
  • AI prefix ; correctly skips completion
  • Fallback works when PTY is stopped
  • 629 pytest tests pass (3 pre-existing failures unrelated to this change)

Summary by CodeRabbit

  • New Features

    • PTY-backed Bash-style command completions for more accurate, cursor-aware suggestions
    • Editor completer wired to access PTY context; completions mark directories and respect cursor position
    • Falls back to PATH-based discovery when PTY/native completion is unavailable; command list built from registry + discovered executables
  • Bug Fixes

    • Internal background commands no longer clear the last user command/error state
  • Tests

    • Added tests for PTY completion and internal-command error handling

…pport

Replace the custom Python completion system (PATH scanning + PathCompleter)
with PTY bash delegation. A new __aish_query_completions function in
bash_rc_wrapper.sh uses compgen and bash-completion functions to provide
context-aware completions (e.g. git subcommands, systemctl units).

Falls back to the original PATH scanning when PTY is unavailable.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

Adds an injectable pty_provider through the prompt/editor stack; extends the completer to query a PTY-backed bash completion helper (with PATH/registry fallback); adds bash-side completion query functions; marks internal PTY-originated commands so they don't alter user-visible last-command/exit-state; and updates tests for both behaviors.

Changes

PTY + Completion Integration

Layer / File(s) Summary
API / Wiring
src/aish/shell/runtime/app.py, src/aish/shell/ui/editor.py
Thread an optional pty_provider: Callable[[], Optional[PTYManager]] into ShellPromptController and construct ShellCompleter with it so completions can access the PTY manager dynamically.
Completer Behavior
src/aish/shell/ui/completion.py
ShellCompleter.__init__ accepts pty_provider. get_completions first attempts PTY-backed Bash-style completion via _query_pty_completions (uses PTY if running, returns non-empty candidates, filters by token prefix, sets start_position = -len(prefix) and early-returns on matches). On PTY unavailability/failure/empty-matches it falls back to _fallback_completions preserving path/command/directory rules. _default_command_provider now builds commands from registry categories + executables on $PATH (removed static COMMON_SHELL_COMMANDS).
Bash-side Completion Helper
src/aish/terminal/pty/bash_rc_wrapper.sh
Adds __aish_mark_dirs() and __aish_query_completions() to compute cmd, cur, prev from line+cursor, load/invoke bash completion functions (or compgen -f fallback), and format results (directories suffixed with /).
Command Source / State
src/aish/terminal/pty/command_state.py
Adds INTERNAL_SOURCE = "internal" and guards updates so results with source == INTERNAL_SOURCE do not overwrite last_command, last_exit_code, last_result, or pending error/correction state.
PTY Execution / Events
src/aish/terminal/pty/manager.py
Execution helpers _exec_via_thread and _exec_via_poll accept *, source: str and forward it to send_command. execute_command uses source="backend", execute_internal_command uses CommandState.INTERNAL_SOURCE. handle_backend_event no longer invokes the exit-code callback for results with source == CommandState.INTERNAL_SOURCE.
Tests
tests/shell/ui/test_shell_editor.py, tests/terminal/pty/test_exit_tracker_repeat_error.py
Adds FakeCompletionPTY test double and test_shell_completer_queries_pty_with_full_line_and_cursor asserting PTY is queried with full line, cursor, timeout and suggestion surfaced. Adds test_internal_command_does_not_clear_user_error_state verifying internal commands don't clear prior user error state.

Sequence Diagram

sequenceDiagram
    participant Editor as ShellPromptController
    participant Completer as ShellCompleter
    participant PTY as PTYManager
    participant Bash as bash_rc_wrapper.sh
    participant Fallback as PathCompleter

    Editor->>Completer: get_completions(line, cursor_pos)
    Completer->>PTY: pty = pty_provider()
    alt PTY available
        Completer->>PTY: query_completions(line, cursor_pos, timeout)
        PTY->>Bash: run __aish_query_completions(line, cursor_pos)
        Bash->>Bash: compute cmd, cur, prev
        Bash->>Bash: invoke completion function or run compgen -f
        Bash->>PTY: return formatted candidates
        PTY->>Completer: (candidates, exit_code)
        Completer->>Completer: filter by token prefix, set start_position
        Completer->>Editor: yield PTY completions
    else PTY unavailable/error/no matches
        Completer->>Fallback: query PATH and registry for candidates
        Fallback->>Completer: candidates
        Completer->>Editor: yield fallback completions
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AI-Shell-Team/aish#117: Modifies PTY-related code, completion sidechannel, and CommandState/PTYManager tracking — closely related to the internal-source and PTY completion changes.

Suggested labels

tests

Poem

🐇 I peek at PTY’s tiny light,

Bash hums hints into the night,
Internal hops keep user tracks,
Completer filters, paths it stacks,
I twitch my whiskers—code feels right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: delegate tab completion to PTY bash' directly and accurately summarizes the main change: shifting tab completion responsibility from the Python-based system to bash running in the PTY.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@github-actions
Copy link
Copy Markdown
Contributor

This pull request description looks incomplete. Please update the missing sections below before review.

Missing items:

  • User-visible Changes
  • Compatibility
  • Testing
  • Change Type
  • Scope

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/aish/shell/ui/completion.py`:
- Around line 116-127: The unconditional return after iterating pty_results
suppresses fallback completions when local filtering leaves zero candidates;
change the logic in the completion generator (the block using pty_results,
current_token and yielding Completion) to only return when at least one
Completion was yielded (e.g., track a boolean yielded flag or detect any
matching candidate), otherwise fall through so fallback completions run instead
of exiting early.

In `@src/aish/terminal/pty/bash_rc_wrapper.sh`:
- Around line 291-323: Replace the manual tokenization loop that builds
words/cword from cmd_line and cursor with a call to bash-completion's helper:
when _get_comp_words_by_ref is available, invoke it to populate COMP_WORDS and
COMP_CWORD (e.g., _get_comp_words_by_ref -n : -- "${cmd_line}" cursor_var), then
set local cmd="${COMP_WORDS[0]:-}", cur="${COMP_WORDS[COMP_CWORD]:-}",
prev="${COMP_WORDS[$((COMP_CWORD-1))]:-}"; if _get_comp_words_by_ref is not
present fall back to the existing parsing logic that uses cmd_line, cursor,
words, cword; ensure the fallback preserves the current behavior but only runs
when the helper is absent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c9965fc2-a17d-4c43-8e8a-9a82bab4d525

📥 Commits

Reviewing files that changed from the base of the PR and between 4d3fd5b and 845e581.

📒 Files selected for processing (4)
  • src/aish/shell/runtime/app.py
  • src/aish/shell/ui/completion.py
  • src/aish/shell/ui/editor.py
  • src/aish/terminal/pty/bash_rc_wrapper.sh

Comment thread src/aish/shell/ui/completion.py
Comment thread src/aish/terminal/pty/bash_rc_wrapper.sh
… out

When PTY returns candidates but none match the current prefix after local
filtering, continue to the fallback completer instead of returning empty.
@jexShain
Copy link
Copy Markdown
Collaborator Author

#147 fixed

Copy link
Copy Markdown
Collaborator

@F16shen F16shen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two blocking issues found during manual verification.

Comment thread src/aish/shell/ui/completion.py Outdated
Comment thread src/aish/shell/ui/completion.py Outdated
@github-actions github-actions Bot added the tests label May 7, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (6)
tests/shell/ui/test_shell_editor.py (2)

15-23: 💤 Low value

Minor: type-annotate calls for clarity.

self.calls = [] has an inferred list[Any] type; an explicit annotation matches the rest of the test module's style and helps readers see the recorded tuple shape.

♻️ Suggested annotation
-class FakeCompletionPTY:
-    def __init__(self, output: str = "status\n") -> None:
-        self.is_running = True
-        self.output = output
-        self.calls = []
+class FakeCompletionPTY:
+    def __init__(self, output: str = "status\n") -> None:
+        self.is_running = True
+        self.output = output
+        self.calls: list[tuple[str, int, float | None]] = []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/shell/ui/test_shell_editor.py` around lines 15 - 23, The test helper
FakeCompletionPTY should explicitly type-annotate its calls attribute to match
module style and document the recorded tuple shape: change the assignment in
FakeCompletionPTY.__init__ so self.calls is declared with a type like
list[tuple[str, int, Optional[float]]] (or the appropriate types for line,
cursor_pos, timeout) instead of an untyped list; update imports if needed and
ensure query_completions appends tuples that conform to that annotation.

282-294: 💤 Low value

Test couples to the hardcoded 500 ms timeout.

The 0.5 literal in the call-tracking assertion mirrors the value baked into ShellCompleter._query_pty_completions. If the timeout is ever made configurable (or tuned), this test will need to be updated in lockstep. Consider asserting on the first two positional args only, or pulling the timeout from a shared constant.

♻️ Optional: decouple from the literal value
-    assert fake_pty.calls == [("git chec kout main", 8, 0.5)]
+    assert len(fake_pty.calls) == 1
+    line, cursor_pos, timeout = fake_pty.calls[0]
+    assert (line, cursor_pos) == ("git chec kout main", 8)
+    assert timeout is not None and timeout > 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/shell/ui/test_shell_editor.py` around lines 282 - 294, The test
test_shell_completer_queries_pty_with_full_line_and_cursor is brittle because it
asserts the hardcoded 0.5 timeout value; update the assertion to avoid coupling
to ShellCompleter._query_pty_completions' internal timeout by only checking the
first two positional args on FakeCompletionPTY.calls (the input text and
cursor_position) or by reading the timeout from a shared constant if one exists;
locate FakeCompletionPTY and ShellCompleter._query_pty_completions in this test
and change the final assertion to assert fake_pty.calls == [("git chec kout
main", 8)] or compare only the slice of the call tuple containing the first two
elements.
src/aish/shell/ui/completion.py (2)

137-158: 💤 Low value

Optional: hoist the PTY-completion timeout to a constant or constructor arg.

timeout=0.5 is duplicated in spirit with the test assertion and is the kind of value most likely to need tuning per environment (slow remote filesystems, heavy bash-completion loaders like __git_complete). Promoting it to a module-level constant or a pty_timeout constructor arg makes both tuning and testing easier without behavior change today.

♻️ Suggested shape
 AI_PREFIXES = (";", ";")
+PTY_COMPLETION_TIMEOUT = 0.5
@@
     def __init__(
         self,
         cwd_provider: Optional[Callable[[], str]] = None,
         command_provider: Optional[Callable[[], Iterable[str]]] = None,
         ai_prefixes: tuple[str, ...] = AI_PREFIXES,
         pty_provider: Optional[Callable[[], Optional["PTYManager"]]] = None,
+        pty_timeout: float = PTY_COMPLETION_TIMEOUT,
     ) -> None:
@@
-        self._pty_provider = pty_provider
+        self._pty_provider = pty_provider
+        self._pty_timeout = pty_timeout
@@
-            output, exit_code = pty_manager.query_completions(
-                line,
-                cursor_pos,
-                timeout=0.5,
-            )
+            output, exit_code = pty_manager.query_completions(
+                line,
+                cursor_pos,
+                timeout=self._pty_timeout,
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aish/shell/ui/completion.py` around lines 137 - 158, Hoist the hard-coded
timeout in _query_pty_completions by adding a configurable pty timeout (either a
module-level constant or a constructor arg on the class that owns
_query_pty_completions) and use that value instead of timeout=0.5 in the call to
pty_manager.query_completions; give the new config a default of 0.5 so behavior
is unchanged, and update any tests that asserted on the literal timeout to
reference the new constant/attribute.

145-152: 💤 Low value

Broad except Exception: is acceptable but consider BaseException boundaries.

Ruff flags BLE001 here. Catching Exception is defensible for a UX fallback path (we never want a PTY hiccup to break the editor), but it will silently swallow programming errors during development. Logging at debug level — without changing the fallback behavior — would preserve resilience while making real bugs discoverable. Not a blocker.

♻️ Suggested change
+import logging
+
+_logger = logging.getLogger(__name__)
@@
-        try:
-            output, exit_code = pty_manager.query_completions(
-                line,
-                cursor_pos,
-                timeout=0.5,
-            )
-        except Exception:
-            return None
+        try:
+            output, exit_code = pty_manager.query_completions(
+                line,
+                cursor_pos,
+                timeout=0.5,
+            )
+        except Exception:  # noqa: BLE001 - completion must never break the editor
+            _logger.debug("PTY completion query failed", exc_info=True)
+            return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aish/shell/ui/completion.py` around lines 145 - 152, The try/except
around pty_manager.query_completions currently swallows all Exceptions silently;
keep the fallback behavior (return None) but log the caught exception at debug
level so programming errors are discoverable during development. Modify the
except Exception: block that surrounds pty_manager.query_completions(line,
cursor_pos, timeout=0.5) to call the module/logger debug method with the
exception info (e.g., logger.debug(..., exc_info=True) or similar) before
returning None, and do not change the return None fallback or broaden to
BaseException.
src/aish/terminal/pty/manager.py (2)

521-546: 💤 Low value

LGTM — clean separation of internal vs backend execution.

execute_internal_command and query_completions are tight wrappers that route through the same _exec_via_* helpers with source=INTERNAL_SOURCE. shlex.quote(line) is the right escaping choice for the bash arg.

One follow-up worth considering: cursor_pos is forwarded as-is to the bash function. The __aish_query_completions bash helper accesses the cursor value directly in substring expansion (${cmd_line:$((cursor-1)):1}) without bounds validation. Negative or out-of-range values would cause unpredictable behavior rather than graceful clamping. A defensive bound on the Python side would make the contract clearer:

♻️ Optional defensive clamp
     def query_completions(
         self, line: str, cursor_pos: int, timeout: Optional[float] = 0.5
     ) -> tuple[str, int]:
         """Query backend bash completions without changing shell command state."""
+        cursor_pos = max(0, min(cursor_pos, len(line)))
         escaped_line = shlex.quote(line)
         command = f"__aish_query_completions {escaped_line} {cursor_pos}"
         return self.execute_internal_command(command, timeout=timeout)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aish/terminal/pty/manager.py` around lines 521 - 546, The
query_completions helper forwards cursor_pos directly to the bash helper
__aish_query_completions, but that bash function uses
${cmd_line:$((cursor-1)):1} and will misbehave for negative or out-of-range
values; clamp and coerce cursor_pos in query_completions to a safe integer
before building the command (e.g. cast to int, ensure cursor = max(1,
min(cursor, len(line))) or otherwise clamp into the valid 1..len(line) range),
then use that clamped value when composing the __aish_query_completions
invocation so execute_internal_command receives a validated cursor argument.

502-538: ⚖️ Poor tradeoff

Update reference from execute_internal_command to execute_command; concern remains valid.

The timeout+Ctrl+C behavior exists in the current execute_command implementation (sent in _exec_via_thread/_exec_via_poll when deadline expires). This method is actively used for completion probes at src/aish/shell/ui/completion.py:0.5 timeout, so the race condition described—where SIGINT could land on a user's foreground process if one started between completion submit and timeout—is theoretically possible, though unlikely. Worth a quick mental check; not necessarily a code change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aish/terminal/pty/manager.py` around lines 502 - 538, Race condition:
timeout-triggered Ctrl+C from execute_command can interrupt a user's foreground
process; inspect _exec_via_thread and _exec_via_poll to harden signal delivery.
Locate the deadline-expiry path in _exec_via_thread/_exec_via_poll (paths used
by execute_command and execute_internal_command) and ensure the interrupt
targets the intended child/PTY process group (e.g., send SIGINT to the child PID
or its process group) instead of writing a raw Ctrl-C to the PTY that could be
delivered to a newly started foreground job; alternatively run completion probes
in a dedicated process group or use an isolated pty/session so timeout signals
cannot race into the user's foreground process. Ensure the chosen fix is applied
consistently for calls from execute_command and for completion probes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/aish/shell/ui/completion.py`:
- Around line 137-158: Hoist the hard-coded timeout in _query_pty_completions by
adding a configurable pty timeout (either a module-level constant or a
constructor arg on the class that owns _query_pty_completions) and use that
value instead of timeout=0.5 in the call to pty_manager.query_completions; give
the new config a default of 0.5 so behavior is unchanged, and update any tests
that asserted on the literal timeout to reference the new constant/attribute.
- Around line 145-152: The try/except around pty_manager.query_completions
currently swallows all Exceptions silently; keep the fallback behavior (return
None) but log the caught exception at debug level so programming errors are
discoverable during development. Modify the except Exception: block that
surrounds pty_manager.query_completions(line, cursor_pos, timeout=0.5) to call
the module/logger debug method with the exception info (e.g., logger.debug(...,
exc_info=True) or similar) before returning None, and do not change the return
None fallback or broaden to BaseException.

In `@src/aish/terminal/pty/manager.py`:
- Around line 521-546: The query_completions helper forwards cursor_pos directly
to the bash helper __aish_query_completions, but that bash function uses
${cmd_line:$((cursor-1)):1} and will misbehave for negative or out-of-range
values; clamp and coerce cursor_pos in query_completions to a safe integer
before building the command (e.g. cast to int, ensure cursor = max(1,
min(cursor, len(line))) or otherwise clamp into the valid 1..len(line) range),
then use that clamped value when composing the __aish_query_completions
invocation so execute_internal_command receives a validated cursor argument.
- Around line 502-538: Race condition: timeout-triggered Ctrl+C from
execute_command can interrupt a user's foreground process; inspect
_exec_via_thread and _exec_via_poll to harden signal delivery. Locate the
deadline-expiry path in _exec_via_thread/_exec_via_poll (paths used by
execute_command and execute_internal_command) and ensure the interrupt targets
the intended child/PTY process group (e.g., send SIGINT to the child PID or its
process group) instead of writing a raw Ctrl-C to the PTY that could be
delivered to a newly started foreground job; alternatively run completion probes
in a dedicated process group or use an isolated pty/session so timeout signals
cannot race into the user's foreground process. Ensure the chosen fix is applied
consistently for calls from execute_command and for completion probes.

In `@tests/shell/ui/test_shell_editor.py`:
- Around line 15-23: The test helper FakeCompletionPTY should explicitly
type-annotate its calls attribute to match module style and document the
recorded tuple shape: change the assignment in FakeCompletionPTY.__init__ so
self.calls is declared with a type like list[tuple[str, int, Optional[float]]]
(or the appropriate types for line, cursor_pos, timeout) instead of an untyped
list; update imports if needed and ensure query_completions appends tuples that
conform to that annotation.
- Around line 282-294: The test
test_shell_completer_queries_pty_with_full_line_and_cursor is brittle because it
asserts the hardcoded 0.5 timeout value; update the assertion to avoid coupling
to ShellCompleter._query_pty_completions' internal timeout by only checking the
first two positional args on FakeCompletionPTY.calls (the input text and
cursor_position) or by reading the timeout from a shared constant if one exists;
locate FakeCompletionPTY and ShellCompleter._query_pty_completions in this test
and change the final assertion to assert fake_pty.calls == [("git chec kout
main", 8)] or compare only the slice of the call tuple containing the first two
elements.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: afc6337d-a6e2-418f-bceb-1f0b26a3554b

📥 Commits

Reviewing files that changed from the base of the PR and between 8c4a85b and f8462d8.

📒 Files selected for processing (5)
  • src/aish/shell/ui/completion.py
  • src/aish/terminal/pty/command_state.py
  • src/aish/terminal/pty/manager.py
  • tests/shell/ui/test_shell_editor.py
  • tests/terminal/pty/test_exit_tracker_repeat_error.py

@F16shen F16shen merged commit c642798 into AI-Shell-Team:main May 7, 2026
11 checks passed
@jexShain jexShain deleted the feat/pty-bash-completion branch May 14, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants