feat(rewrite): translate PowerShell cmdlets to rtk subcommands - #3439
feat(rewrite): translate PowerShell cmdlets to rtk subcommands#3439make0uthill wants to merge 2 commits into
Conversation
The RULES table keys off the command word, so PowerShell cmdlets — which
share no name with their GNU counterparts — never match it. On Windows the
agent reaches for `Get-ChildItem` and `Select-String` rather than `ls` and
`grep`, so those calls reached the model as unfiltered output and the hook
saved nothing.
Translates the three cmdlets whose semantics map cleanly onto an rtk
subcommand, plus their common aliases (`gc`, `gci`, `dir`, `sls`):
Get-Content foo.txt -TotalCount 5 -> rtk read foo.txt --max-lines 5
Get-ChildItem src -Recurse -> rtk ls -R src
Select-String -Path a.txt -Pattern rtk -> rtk grep -i rtk a.txt
The `-i` on Select-String is not cosmetic: the cmdlet matches
case-insensitively by default while grep does not, so omitting it would
silently narrow the result set.
Deliberately narrow. A cmdlet carrying any parameter without a faithful rtk
equivalent (`-Filter`, `-Raw`, `-File`, `-ErrorAction`) returns None and runs
unrewritten — mistranslating a flag changes what the command means, which is
worse than forgoing the saving. Cmdlets are also only rewritten in
RewriteContext::Normal: as a pipeline stage a cmdlet hands .NET objects to
the next stage, and rtk's text output would not survive that.
Argument splitting cannot reuse shell_split, which treats a backslash as an
escape and would turn `D:\Code\x` into `D:Codex`. ps_split keeps backslashes
literal and preserves quoting so a rewrite re-emits paths exactly as written.
Adds 8 tests covering the translations, the pass-through cases, Windows
paths, and pipeline stages.
|
|
Follow-up to the review note in this PR: a name filter or a type constraint
makes Get-ChildItem a search rather than a listing, and that maps faithfully
onto find.
Get-ChildItem src -Recurse -Filter *.rs -> rtk find src -name '*.rs'
Get-ChildItem -Recurse -File -> rtk find . -type f
Get-ChildItem -Recurse -Directory -> rtk find . -type d
Without -Recurse the search is depth-limited with -maxdepth 1: Get-ChildItem
only descends when asked, while find recurses by default.
-Force is dropped rather than translated when routing to find — it makes
Get-ChildItem include hidden entries, which is already find's default.
Still passed through: -Include with a comma-separated list, which would need
`find ( -name a -o -name b )`, and -File combined with -Directory.
|
Pushed the follow-up: Without Full suite green, 2571 passed. |
|
Correction to my note above: the suite is 2563 passed, 0 failed (I quoted 2563 as 2571 by mistake). Nothing else in that comment changes. |
Summary
The
RULEStable keys off the command word, so PowerShell cmdlets — which share no name with their GNU counterparts — never match it. On Windows the agent reaches forGet-ChildItemandSelect-Stringrather thanlsandgrep, so those calls reach the model as unfiltered output and the hook saves nothing.Translates the three cmdlets whose semantics map cleanly onto an rtk subcommand, plus their common aliases (
gc,gci,dir,sls):Two details worth flagging for review:
-ionSelect-Stringis not cosmetic: the cmdlet matches case-insensitively by default whilegrepdoes not, so omitting it would silently narrow the result set.shell_split, which treats a backslash as an escape and would turnD:\Code\xintoD:Codex.ps_splitkeeps backslashes literal and preserves quoting.Deliberately narrow. A cmdlet carrying any parameter without a faithful rtk equivalent (
-Filter,-Raw,-File,-ErrorAction) returnsNoneand runs unrewritten — mistranslating a flag changes what the command means, which is worse than forgoing the saving. Cmdlets are also only rewritten inRewriteContext::Normal: as a pipeline stage a cmdlet hands .NET objects to the next stage, and rtk's text output would not survive that.Known gap, left for a follow-up:
Get-ChildItem -Recurse -Filter *.rscould map faithfully ontortk find . -name '*.rs'(and-File/-Directoryonto-type f/-type d). Happy to add it here instead if you'd prefer it in one PR.Test plan
cargo fmt --all && cargo clippy --all-targets && cargo test— 2562 passed, 0 failedrtk hook claudewith aPowerShelltool payload; rewritten and passed-through cases both behave as the tests describe.Targets
developas required.