Skip to content

fix: rename reserved $input variable in PowerShell hooks - #17

Merged
developzoneio merged 1 commit into
hotfix/ps-hooks-auditfrom
fix/ps-hooks-input-var-collision
Jul 2, 2026
Merged

fix: rename reserved $input variable in PowerShell hooks#17
developzoneio merged 1 commit into
hotfix/ps-hooks-auditfrom
fix/ps-hooks-input-var-collision

Conversation

@developzoneio

Copy link
Copy Markdown
Owner

Summary

  • All three PowerShell hooks (subagent-retro.ps1, prompt-router.ps1, spec-gate.ps1) assigned parsed hook JSON to $input, PowerShell's reserved automatic pipeline variable.
  • On real piped/redirected stdin - exactly how Claude Code invokes hooks - that assignment throws a non-terminating ParameterBindingException and leaves $input unbound, so every PowerShell hook exits before reading any input at all.
  • Renamed to $hookInput in all three files. Reproduced and confirmed on both PowerShell 7 (pwsh) and Windows PowerShell 5.1.
  • Discovered while reproducing the fixture for the 01-bug-subagent-retro-ps1-matches-clobber.md audit item - that bug was unreachable until this one was fixed, so it's split into its own PR ahead of it.

Test plan

  • printf '{"cwd":"..."}' | pwsh -File hooks/powershell/subagent-retro.ps1 now reads stdin and produces output instead of erroring silently
  • Smoke-tested prompt-router.ps1 and spec-gate.ps1 with representative JSON - both exit 0 and produce expected output
  • grep -nP "[^\x00-\x7F]" hooks/powershell/*.ps1 install/*.ps1 - no matches (pure ASCII preserved)
  • .\scripts\validate.ps1 - all checks pass
  • CHANGELOG [Unreleased] entry added

🤖 Generated with Claude Code

Assigning parsed hook JSON to $input (PowerShell's automatic pipeline
variable) throws a non-terminating ParameterBindingException whenever
the hook receives real piped/redirected stdin - i.e. on every actual
Claude Code invocation. The assignment silently fails, $input stays
unbound, and the hook exits before reading any input. Renamed to
$hookInput in subagent-retro.ps1, prompt-router.ps1, and spec-gate.ps1.

Discovered while reproducing the 01-bug-subagent-retro-ps1-matches-clobber
fixture; that bug was unreachable until this one was fixed.
@developzoneio
developzoneio merged commit cbff63a into hotfix/ps-hooks-audit Jul 2, 2026
4 checks passed
@developzoneio
developzoneio deleted the fix/ps-hooks-input-var-collision branch July 2, 2026 04:00
developzoneio added a commit that referenced this pull request Jul 5, 2026
* fix: rename reserved $input variable in PowerShell hooks (#17)

Assigning parsed hook JSON to $input (PowerShell's automatic pipeline
variable) throws a non-terminating ParameterBindingException whenever
the hook receives real piped/redirected stdin - i.e. on every actual
Claude Code invocation. The assignment silently fails, $input stays
unbound, and the hook exits before reading any input. Renamed to
$hookInput in subagent-retro.ps1, prompt-router.ps1, and spec-gate.ps1.

Discovered while reproducing the 01-bug-subagent-retro-ps1-matches-clobber
fixture; that bug was unreachable until this one was fixed.

* fix: stop $Matches clobber in subagent-retro.ps1 spec-ID extraction (#18)

* fix: rename reserved $input variable in PowerShell hooks

Assigning parsed hook JSON to $input (PowerShell's automatic pipeline
variable) throws a non-terminating ParameterBindingException whenever
the hook receives real piped/redirected stdin - i.e. on every actual
Claude Code invocation. The assignment silently fails, $input stays
unbound, and the hook exits before reading any input. Renamed to
$hookInput in subagent-retro.ps1, prompt-router.ps1, and spec-gate.ps1.

Discovered while reproducing the 01-bug-subagent-retro-ps1-matches-clobber
fixture; that bug was unreachable until this one was fixed.

* fix: stop $Matches clobber in subagent-retro.ps1 spec-ID extraction

Get-IndexSpecs ran the spec-ID regex -match before the in-progress
literal -match, so the second match overwrote $Matches and every
in-progress spec was reported under the literal ID "in-progress"
rather than its real ID. The retro-staleness check then looked for
<specDir>/in-progress/05-retro.md, which never exists, so every
in-progress spec was reported stale under the wrong ID.

Swap the match order (in-progress first, ID regex last) to match
the already-correct sister hooks prompt-router.ps1:167 and
spec-gate.ps1:145.

Verified against a fixture index (FEAT-123 in-progress, RCA-77
in-progress) - PowerShell now reports FEAT-123 and skips the RCA
row, matching hooks/bash/subagent-retro.sh output exactly.

* fix: same-line in-progress detection parity in spec-gate.sh

bash used two independent file-wide greps for the in-progress marker
and a spec ID, letting a legend/header line combine with an unrelated
done row. spec-gate.ps1 and prompt-router.sh already require both on
the same line; spec-gate.sh now matches.

* fix: align feature.md and refactor.md subagent field names with contracts

sd-spec-architect and sd-code-explorer read TASK/SPEC/IMPACT, not the
TASK_TYPE/SPEC_REF/IMPACT_REF/TICKET_DATA names feature.md sent them.
Both refine invocations were also missing the required SPEC path, and
the TEMPLATE field was bare instead of the full template filename.
refactor.md's characterization-test loop sent sd-implementer an
unrecognized TASK_TYPE field instead of TASK_DETAILS/SPEC_REF/
WORKFLOW_TYPE. Reviewer invocations, which own TASK_TYPE/SPEC_REF as
their own contract, are unchanged.

* fix: make /sd:spec validate plan/tasks check type-aware

The in-progress file-presence rule exempted only RCA from requiring
01-plan.md/02-tasks.md, but bug and perf workflows never produce those
artifacts either (their artifact set is spec, decisions, artifacts,
retro). Validate failed every correctly executed bug/perf spec.
Narrowed the requirement to feature and refactor, and fixed the same
overgeneralized claim in docs/usage.md's resume heuristic.

* fix: parse debounce timestamp as UTC in subagent-retro.ps1

[datetime]::Parse of a "...Z" string returns Kind=Local, converted
from UTC to local time. Subtracting that from a UTC now skewed $age
by the machine's UTC offset -- wrongly suppressing reminders on
UTC+N machines, never suppressing on UTC-N. Verified on a UTC+7
machine under Windows PowerShell 5.1 (the hooks' target runtime):
old code showed a 420-minute skew immediately after save; fixed code
shows ~0.

* fix: apply per-workflow keyword defaults in prompt-router.ps1

PS only fell back to built-in defaults when project-config.json was
absent or unparseable, then silently skipped any workflow whose
keyword list was null once a config file existed. A valid config
that omitted workflow.keywords (or one workflow's entry) lost
keyword routing hints on Windows while bash kept emitting them from
defaults, matching bash's per-workflow "// []" + empty-list fallback
semantics. Verified against both a config missing workflow.keywords
entirely and one overriding a single workflow, under Windows
PowerShell 5.1.

* fix: replace stale MCP tool names in agents, skills, and explore command

* fix: remove hardcoded MSSQL/C#/TS stack references from agents and commands

* fix: code-explorer impact-map returns analysis instead of self-appending

* fix: walk full lifecycle state machine in bug/rca/perf workflows

* fix: guard workflow Phase 0 against missing or malformed Layer-2 context

* refactor: dedup rules copy-pasted from skills into agent/command bodies

* docs: fix README/ROADMAP/usage drift after v1.3.0+ shipped

* refactor: derive validate.sh/ps1 install counts from source tree

* feat: add macOS to CI matrix and hook smoke tests

Also fixes two PowerShell-7-only debounce bugs in subagent-retro.ps1
that the new smoke test caught: an unresolvable Split-Path parameter
set, and re-Parse-ing an already-converted [datetime] as local time.

* fix: harden install.sh - strict mode, prefix guard, quoting

* fix: strip CRLF from jq keyword output in prompt-router.sh

Some jq builds (observed with Windows jq.exe) emit CRLF for join("\n")
output even from LF-only input, so every keyword but a workflow's last
kept a trailing \r and never matched, silently dropping keyword-routing
hints whenever project-config.json defined workflow.keywords. Fixture
in scripts/smoke-hooks.sh/.ps1 now sets workflow.keywords so this path
is actually exercised.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: make prompt-router.sh bash 3.2 compatible

macOS runners execute hooks with system bash 3.2, which has no
associative arrays: declare -A silently failed and every string
subscript arithmetic-evaluated to 0, so the router emitted
'- /sd:0' instead of '- /sd:bug' and the macOS smoke test failed.
Replace the two associative arrays with parallel indexed arrays.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: add review findings TODO before merge

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant