feat: clearer Arguments editor with typed-together detection and one-click fix

- Label now explains the model with an example: a flag and its value go
  on separate lines. Placeholder shows the common uv pattern.
- split_suspicious_args() flags lines that contain whitespace plus a
  dash-prefixed token ('--directory /path') — legit single args with
  spaces ('My Documents') are never touched. Quotes are respected.
- The editor shows a warning under the args box with a 'Fix: split onto
  separate lines' button; the fix goes through the undo stack.
This commit is contained in:
AJ
2026-07-02 00:13:06 -04:00
parent 77f469c1dd
commit e11886bde9
3 changed files with 119 additions and 4 deletions
+49 -4
View File
@@ -360,14 +360,30 @@ class ServerEditor(QFrame):
self.command.setPlaceholderText("npx, uvx, node, python3, or a full path")
self.command.textChanged.connect(self._emit)
v.addWidget(self.command)
v.addWidget(self._lbl("Arguments (one per line)"))
self.args = ArgsEdit()
self.args.setPlaceholderText(
"-y\n@modelcontextprotocol/server-filesystem\n/Users/you/Documents"
args_lbl = self._lbl(
"Arguments — each line is one argument. A flag and its value go on "
"separate lines, e.g. “--directory” on line 1, “/path/to/server” on line 2."
)
args_lbl.setWordWrap(True)
v.addWidget(args_lbl)
self.args = ArgsEdit()
self.args.setPlaceholderText("--directory\n/path/to/your/server\nrun\nmain.py")
self.args.setMinimumHeight(70)
self.args.textChanged.connect(self._emit)
v.addWidget(self.args, 1)
# Shown when a line looks like several arguments typed together.
self.args_warn = QLabel("")
self.args_warn.setStyleSheet(f"color: {WARN};")
self.args_warn.setWordWrap(True)
self.args_warn.hide()
self.args_fix_btn = QPushButton("Fix: split onto separate lines")
self.args_fix_btn.clicked.connect(self._fix_args)
self.args_fix_btn.hide()
warn_row = QHBoxLayout()
warn_row.addWidget(self.args_warn, 1)
warn_row.addWidget(self.args_fix_btn)
v.addLayout(warn_row)
v.addWidget(self._lbl("Environment variables"))
self.env = KeyValueTable(
"Variable", "Value", on_change=self._emit, before_change=self._before_change
@@ -411,6 +427,8 @@ class ServerEditor(QFrame):
self.details_btn.setChecked(False)
self.diag_text.clear()
self._set_dep({"status": "unknown", "label": ""})
self.args_warn.hide()
self.args_fix_btn.hide()
self._loading = False
return
self.setEnabled(True)
@@ -440,6 +458,7 @@ class ServerEditor(QFrame):
self.env.load(d.get("env", {}))
self._loading = False
self.refresh_dependency(auto_open=True)
self._check_args()
def dump_data(self) -> dict:
"""Build the server dict from the form, preserving unknown fields."""
@@ -485,6 +504,32 @@ class ServerEditor(QFrame):
if not self._loading and self._on_change:
self._on_change()
self.refresh_dependency(auto_open=False)
self._check_args()
# --- args sanity check ------------------------------------------------ #
def _current_arg_lines(self) -> list[str]:
return [ln for ln in self.args.toPlainText().splitlines() if ln.strip() != ""]
def _check_args(self):
"""Warn (and offer a fix) when a line looks like several args in one."""
if self.type.currentIndex() != 0: # stdio page only
self.args_warn.hide()
self.args_fix_btn.hide()
return
_, notes = core.split_suspicious_args(self._current_arg_lines())
if notes:
self.args_warn.setText("" + "\n".join(notes))
self.args_warn.show()
self.args_fix_btn.show()
else:
self.args_warn.hide()
self.args_fix_btn.hide()
def _fix_args(self):
if self._before_change:
self._before_change()
fixed, _ = core.split_suspicious_args(self._current_arg_lines())
self.args.setPlainText("\n".join(fixed)) # triggers _emit -> recheck
# --- dependency ------------------------------------------------------ #
def refresh_dependency(self, auto_open=False):