Windows scripts — the win/*.ps1 ports
Audience: anyone maintaining the Windows dispatch path. This is an inventory + the load-bearing compatibility notes; the edit-one-edit-both parity rule and the diff loop live in the repo-root
AGENTS.md("Touched a_shared/scripts/posix/*.sh? Itswin/*.ps1twin must stay in sync"). Re-verify parity there after changing any twin.
The five skill-invoked scripts plus one operator helper are shipped twice:
- POSIX path:
skills/_shared/scripts/posix/<name>.sh(bash originals) - Windows path:
skills/_shared/scripts/win/<name>.ps1(PowerShell ports)
The three SKILL.md files contain one dispatch rule each — "run every
bash …/scripts/X.sh shown in this skill as pwsh or powershell
(…/scripts/win/X.ps1) with the same arguments" — and each skill picks
that branch itself, from its own runtime, before the first script runs.
statuscheck's platform row then confirms the OS (and, on Windows,
that the runtime + ports are present) — it can't be the source the
dispatch is keyed off, since statuscheck is itself one of the dispatched
scripts. So a skill never names a .ps1 directly; it names the .sh and
the dispatch rule maps it.
Quick reference
All paths below are relative to the plugin root (plugins/jira-sdlc/).
| Script | Path | Summary | Called by |
|---|---|---|---|
statuscheck | skills/_shared/scripts/win/statuscheck.ps1 --role <role> | Pre-flight healthcheck: one markdown table of env facts (git/worktree, branch, issue key, platform, gh+Jira auth, project config). Exit 0 if all OK, 1 if any FAIL, 2 on a bad/missing --role. --role is required and selects the credential its jira_auth row probes; its platform row confirms POSIX-bash vs Windows-ps1 dispatch (already chosen by the skill up front). | assigner, executor, reviewer — each skill's "Discovery & healthcheck" |
ensure_local_env | skills/_shared/scripts/win/ensure_local_env.ps1 | Gives a linked worktree the whole .jst/ contract — .gitignore, jira-sdlc-tools.env, jira-sdlc-tools.local.env — copying each from the main checkout when absent (creating .jst/ there if needed) and never overwriting. Refuses to write the credential file unless git ignores that path in the worktree, establishing the .jst/.gitignore rule first. No-op in the main checkout. Exit 0/1. | assigner, executor, reviewer — run first in each skill (before login, before statuscheck); also invoked as a child by statuscheck.ps1's own env_local gate |
get_assignee_email | skills/_shared/scripts/win/get_assignee_email.ps1 | Prints the email every issue should be assigned to (JIRA_EXECUTOR_EMAIL, required — no fallback). One line on stdout. Exit 0/1, reason on stderr. | assigner only (to set sub-task assignees) |
check_assignee | skills/_shared/scripts/win/check_assignee.ps1 [--role <role>] [ISSUE-KEY] | Is this issue assigned to the account jira.ps1 authenticates as? Compares accountId (not email — email is hidden on others' assignee objects). Exit 0 = mine → CONTINUE; 1 = unassigned / someone else / unreadable → STOP + fix on stderr. | executor only (before working an issue) |
list_subtasks | skills/_shared/scripts/win/list_subtasks.ps1 -Parent <KEY> [-Role <role>] [-EnvPath …] [-Json] | Lists a Jira parent's sub-tasks (key + summary); jira.ps1 issue view omits subtasks by default, so it requests subtasks,issuetype. Text or -Json output. Exit 0/1/ | None of the three skills (they fetch subtasks inline). Operator/standalone helper a human runs from the CLI; documented in docs/JIRA-REST.md §10 |
Note on
list_subtasks: its POSIX sibling isskills/_shared/scripts/posix/list_subtasks.sh— a bash original like the other five, in the normal bash↔ps1 parity loop. One asymmetry remains: the bash twin requiresjqto address the nested per-sub-task fields reliably (see the script's own comment), while the.ps1port still needs neitherpython3norjq(see "No python, no jq" below) — so on ajq-less POSIX box, the.ps1port run underpwshis still the one that works.
PowerShell 5.1 + 7 compatibility (load-bearing)
Every win/*.ps1 port runs on both Windows PowerShell 5.1 (powershell.exe,
shipped with Windows) and PowerShell 7 (pwsh, installed separately). They
contain no PS7-only syntax — no ternary ?:, null-coalescing ??,
pipeline-chain &&/||, and no reliance on the $IsWindows/$IsMacOS/$IsLinux
automatic variables (those are PS6+, undefined on 5.1). Concretely:
- OS detection uses
$env:OS -eq 'Windows_NT'(statuscheck.ps1'sGet-DetectedOS), with an explicit$null -eq $IsWindowsfallback so 5.1 falls through to the$env:OSbranch. - Child exec (
statuscheck.ps1delegating toensure_local_env.ps1) is runtime-agnostic: it picks$PSHOME\pwsh.exeif present, otherwise$PSHOME\powershell.exe. statuscheck.sh's platform row (the POSIX twin, the source the skills' dispatch reads) triespwshfirst, then falls back topowershell, accepting version ≥ 5.
Invocation
# PowerShell 7 (if installed) — default ExecutionPolicy is RemoteSigned, no bypass needed:
pwsh -NoProfile -File skills/_shared/scripts/win/<name>.ps1 [args]
# Windows PowerShell 5.1 ( shipped with Windows ) — default policy is Restricted:
powershell -NoProfile -ExecutionPolicy Bypass -File skills/_shared/scripts/win/<name>.ps1 [args]
The -ExecutionPolicy Bypass on the 5.1 form is not optional on a stock Windows
install: 5.1's default policy is Restricted, which refuses to load any
.ps1; 7 defaults to RemoteSigned, which loads local unsigned scripts fine.
Verified
(Ported during JST-94.) All six ports pass the language tokenizer
(System.Management.Automation.Language.Parser::ParseFile) on both runtimes
and were live-run on a real Windows 11 box against a real Jira instance under:
- Windows PowerShell 5.1.26100.6584 (the only runtime initially on the box —
no
pwsh), and - PowerShell 7.6.3 (installed via
winget install Microsoft.PowerShell; it installs alongside 5.1 —pwsh↔ 7,powershell↔ 5.1, nothing overwritten).
statuscheck.ps1 reports PowerShell 5 + … or PowerShell 7 + … under the
respective runtime; check_assignee.ps1 and
list_subtasks.ps1 were exercised live against Jira under both.
One gotcha to never undo
1. No python, no jq — the ports are dependency-free
The win/*.ps1 ports parse jira.ps1's JSON output (and, for list_subtasks,
the subtask list) with PowerShell's built-in ConvertFrom-Json — they need
neither python3 nor jq. This matters on default Windows 11, where python3
on PATH is an "App Execution Alias" stub (prints a Microsoft Store nag, exits
non-zero — not real Python): the bash check_assignee.sh, which parses
with … | python3 -c … 2>/dev/null || true, silently fails there and
false-reports "UNASSIGNED". The ps1 twin is correct there. (Confirmed on the
JST-94 box.) The python dependency is a bash-twin Windows fragility, out of
this port's scope by design — the Windows dispatch path is ps1 precisely to
side-step it.
See also
- Repo-root
AGENTS.md→ "Touched a_shared/scripts/posix/*.sh? Itswin/*.ps1twin must stay in sync" — the parity contract, theSTATUSCHECK_FORCE_OS-forced bash↔pwsh diff loop, and the residual Windows-only surface a Linux+pwsh diff can't reproduce. docs/JIRA-REST.md§10 —list_subtasks.sh/create_parent_and_subtasks.shoperator helpers (the ps1 twin is the Windows form of the former).skills/_shared/project-config.md— the.jst/jira-sdlc-tools.env/.jst/jira-sdlc-tools.local.envvariables the ports resolve (PROJECT-KEY, JIRA_EMAIL, JIRA_TOKEN, JIRA_ACCOUNT_URL, status names, etc.).