review followup: empty-input guards, ~/ symmetry, CMD: filter

Addresses three concerns + one nit from the Phase 0 review pass.

executor.lua:
  - M.exec guards empty / whitespace-only cmd up front, returns
    "(empty command)" / -1 instead of running the wrapper on nothing.
  - On sentinel-parse failure with empty output (typical of shell
    parse errors — the syntax error itself escapes to the popen
    parent's stderr because 2>&1 is inside the unparsable subshell),
    surface "(no output — possible shell parse error)" rather than
    a silent empty frame.
  - extract_cmd_lines now skips whitespace-only / empty bodies; a
    bare `CMD: ` line in assistant output no longer turns into an
    "execute ''? [y/N]" prompt.
  - "what" comments cleaned in maybe_chdir.

router.lua:
  - path_like now matches `~` and `~/foo` so `~/scripts/build.sh`
    classifies as shell (was: ai). Restores symmetry with executor's
    maybe_chdir, which already expands `~` on `cd`.

repl.lua:
  - :exec and :ask trim args and renderer.status a usage line on
    empty rather than running an empty cmd / sending an empty turn
    to broker.

Regression: full prior smoke suite still passes — known_commands
shell paths, all maybe_chdir branches, CMD: extraction with non-empty
bodies, exec exit-code recovery, all router branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 17:41:35 +00:00
parent a18e530c03
commit abc993aa49
3 changed files with 28 additions and 11 deletions
+6 -3
View File
@@ -25,11 +25,14 @@ local function known_commands_set(config)
return set
end
-- §5.1 path-like: ./foo, ../foo, /usr/bin/foo. Quoted/escaped paths are
-- intentionally out of scope in Phase 0.
-- §5.1 path-like: ./foo, ../foo, /usr/bin/foo, ~/foo, bare ~. Quoted /
-- escaped paths are intentionally out of scope in Phase 0. ~ is included
-- for symmetry with executor.maybe_chdir, which expands ~ on `cd ~/foo`.
local function path_like(token)
return token:sub(1, 1) == "/"
return token == "~"
or token:sub(1, 1) == "/"
or token:sub(1, 2) == "./"
or token:sub(1, 2) == "~/"
or token:sub(1, 3) == "../"
end