mirror of
https://github.com/instructkr/claude-code.git
synced 2026-05-16 19:06:44 +00:00
Prevent plugin command aliases from becoming prompts
Added focused Python-port regressions for plugin, plugins, marketplace, and reload-plugins command routing, execution, stream, and turn-loop paths; narrowed runtime routing to honor explicit leading commands before fuzzy inventory matches. Constraint: Task 10 scope limited changes to tests/test_porting_workspace.py plus narrow src parser/runtime fixes only if required. Rejected: Test-only coverage without alias routing fix | route /plugin previously preferred fuzzy AddMarketplace over exact plugin command. Confidence: high Scope-risk: narrow Directive: Keep --no-plugin-commands excluding plugin source hints; do not reinterpret that intentional filter as fallthrough. Tested: python3 -m unittest tests.test_porting_workspace; python3 -m compileall src tests/test_porting_workspace.py; CLI route/turn-loop/filter smoke for /plugin, /plugins, /marketplace, /reload-plugins. Not-tested: Full repository non-Python/Rust suites.
This commit is contained in:
@@ -35,6 +35,11 @@ def load_command_snapshot() -> tuple[PortingModule, ...]:
|
||||
|
||||
PORTED_COMMANDS = load_command_snapshot()
|
||||
|
||||
COMMAND_ALIASES = {
|
||||
'plugins': 'plugin',
|
||||
'marketplace': 'plugin',
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def built_in_command_names() -> frozenset[str]:
|
||||
@@ -50,7 +55,7 @@ def command_names() -> list[str]:
|
||||
|
||||
|
||||
def get_command(name: str) -> PortingModule | None:
|
||||
needle = name.lower()
|
||||
needle = COMMAND_ALIASES.get(name.lower(), name.lower())
|
||||
for module in PORTED_COMMANDS:
|
||||
if module.name.lower() == needle:
|
||||
return module
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from .commands import PORTED_COMMANDS
|
||||
from .commands import PORTED_COMMANDS, get_command
|
||||
from .context import PortContext, build_port_context, render_context
|
||||
from .history import HistoryLog
|
||||
from .models import PermissionDenial, PortingModule
|
||||
@@ -88,6 +88,7 @@ class RuntimeSession:
|
||||
|
||||
class PortRuntime:
|
||||
def route_prompt(self, prompt: str, limit: int = 5) -> list[RoutedMatch]:
|
||||
explicit_command = self._explicit_command_match(prompt)
|
||||
tokens = {token.lower() for token in prompt.replace('/', ' ').replace('-', ' ').split() if token}
|
||||
by_kind = {
|
||||
'command': self._collect_matches(tokens, PORTED_COMMANDS, 'command'),
|
||||
@@ -95,6 +96,16 @@ class PortRuntime:
|
||||
}
|
||||
|
||||
selected: list[RoutedMatch] = []
|
||||
if explicit_command is not None:
|
||||
selected.append(explicit_command)
|
||||
by_kind['command'] = [
|
||||
match
|
||||
for match in by_kind['command']
|
||||
if not (
|
||||
match.name == explicit_command.name
|
||||
and match.source_hint == explicit_command.source_hint
|
||||
)
|
||||
]
|
||||
for kind in ('command', 'tool'):
|
||||
if by_kind[kind]:
|
||||
selected.append(by_kind[kind].pop(0))
|
||||
@@ -106,6 +117,22 @@ class PortRuntime:
|
||||
selected.extend(leftovers[: max(0, limit - len(selected))])
|
||||
return selected[:limit]
|
||||
|
||||
@staticmethod
|
||||
def _explicit_command_match(prompt: str) -> RoutedMatch | None:
|
||||
first_token = prompt.strip().split(maxsplit=1)[0] if prompt.strip() else ''
|
||||
command_name = first_token.removeprefix('/')
|
||||
if not command_name:
|
||||
return None
|
||||
module = get_command(command_name)
|
||||
if module is None:
|
||||
return None
|
||||
return RoutedMatch(
|
||||
kind='command',
|
||||
name=module.name,
|
||||
source_hint=module.source_hint,
|
||||
score=100,
|
||||
)
|
||||
|
||||
def bootstrap_session(self, prompt: str, limit: int = 5) -> RuntimeSession:
|
||||
context = build_port_context()
|
||||
setup_report = run_setup(trusted=True)
|
||||
|
||||
Reference in New Issue
Block a user