Severity: π΄ Critical (silent breakage of @query)
In src/perseus/directives/query.py, the timeout=N modifier is stripped from raw AFTER cmd was extracted (lines ~75β85):
cmd_match = re.match(r'^"((?:[^"\\]|\\.)*)"', raw) # ~75
...
else:
cmd = cmd_raw # ~85
...
timeout = int(cfg["render"].get("query_timeout_s", 30))
tm_match = re.search(r'\s+timeout=(\d+)(?:\s|$)', raw) # ~98
if tm_match:
timeout = int(tm_match.group(1))
raw = (raw[:tm_match.start()] + raw[tm_match.end():]).rstrip() # mutates raw, not cmd
For unquoted commands, cmd = cmd_raw captures the entire raw including timeout=10. The re.sub only modifies raw, never cmd. The executed shell command therefore contains the literal text timeout=10.
Repro
@query git status timeout=10
Expected: git status runs with 10s timeout.
Actual: git status timeout=10 runs (invalid; subprocess returns nonzero with confusing error).
Suggested fix
Hoist modifier extraction above cmd extraction:
# Extract timeout=N modifier first
timeout = int(cfg["render"].get("query_timeout_s", 30))
tm_match = re.search(r'\s+timeout=(\d+)(?:\s|$)', raw)
if tm_match:
timeout = int(tm_match.group(1))
raw = (raw[:tm_match.start()] + raw[tm_match.end():]).rstrip()
# Now extract command
cmd_match = re.match(r'^"((?:[^"\\]|\\.)*)"', raw)
...
Apply the same hoisting discipline for fallback= and schema= if they could similarly leak.
Acceptance criteria
- Test:
@query git status timeout=5 β cmd == "git status", timeout == 5.
- Test:
@query "echo foo timeout=10" β cmd == "echo foo timeout=10" (literal inside quotes), default timeout.
Severity: π΄ Critical (silent breakage of
@query)In
src/perseus/directives/query.py, thetimeout=Nmodifier is stripped fromrawAFTERcmdwas extracted (lines ~75β85):For unquoted commands,
cmd = cmd_rawcaptures the entirerawincludingtimeout=10. There.subonly modifiesraw, nevercmd. The executed shell command therefore contains the literal texttimeout=10.Repro
Expected:
git statusruns with 10s timeout.Actual:
git status timeout=10runs (invalid; subprocess returns nonzero with confusing error).Suggested fix
Hoist modifier extraction above
cmdextraction:Apply the same hoisting discipline for
fallback=andschema=if they could similarly leak.Acceptance criteria
@query git status timeout=5βcmd == "git status",timeout == 5.@query "echo foo timeout=10"βcmd == "echo foo timeout=10"(literal inside quotes), default timeout.