All notable changes to the Pipeline-Check VS Code extension. The format follows Keep a Changelog; versions follow SemVer.
⚠ Release note for publish.yml: the release-notes extractor (an
awkscript in publish.yml) prints every line between the first and second## [headers. When cutting a release, fold the entries under## [Unreleased]into the new## [X.Y.Z] — <date>section above Unreleased, or remove the Unreleased block for the release commit. Otherwise the GitHub release ships boilerplate.
Recovery republish of v1.5.0 — the VS Code Marketplace publish step
timed out on _apis/gallery (Azure DevOps gallery API,
Microsoft-side) and vsce publish returned non-zero before the
upload was committed. Open VSX and the GitHub release for v1.5.0
both shipped fine on the original tag push; only Marketplace
missed it, leaving Marketplace users stuck on 1.1.0 while OVSX
users got 1.5.0. This tag exists solely to re-fire the publish
pipeline so Marketplace catches up. No source changes between
v1.5.0 and v1.5.1.
- Version bump only — no functional changes. v1.5.0 is the identical extension code; Open VSX users will see a 1.5.0 → 1.5.1 update with no behavioural diff. VS Code Marketplace users skip 1.5.0 entirely (it was never published there).
Aligns the extension's version stream with the upstream
pipeline-check engine's
1.5.x line so users can read the two side-by-side without doing the
mapping in their head. No skipped functionality between 1.1.0 and
1.5.0 — the only user-visible change is the engine-update notifier
below.
- Daily PyPI poll for a newer engine. Once per 24 h (per-session
latch + per-day
globalStatetimestamp), the extension querieshttps://pypi.org/pypi/pipeline-check/jsonafter a successful preflight and surfaces a non-blocking notification when PyPI's latest stable is newer than the engine the user has installed. The Upgrade in terminal action runs the existingupgradeInTerminalflow — terminal opens,python -m pip install --upgrade "pipeline-check[lsp]"is typed but not auto-executed, same review-then-Enter pattern as the install CTA. Skip this version silences the prompt for that exact version only; a later release re-prompts. Dismissing the toast (no choice) re-prompts on the next per-day window. Every failure path (offline, PyPI 5xx, malformed JSON, timeout) is silent — failures land in the Pipeline-Check output channel, not in a user-facing toast for a background nicety they didn't ask about. Independent of the hardMIN_ENGINE_VERSIONfloor in src/preflight.ts, which still drives the Upgrade welcome panel when the installed engine is too old to support the extension's features. New settingpipelineCheck.engineUpdates.checkEnabled(defaulttrue) turns the check off entirely.
Feature batch on top of v1.0.3. Three user-visible additions plus
infrastructure for a fourth: a Findings-panel severity quick-filter
(mute MEDIUM while triaging CRITICAL without touching the editor-wide
threshold setting), a quick-fix lightbulb on every diagnostic (Open
docs / Copy rule ID / Reveal in panel), and a fast-fail engine
preflight that surfaces the install or upgrade action in under a
second instead of waiting out the 30-second LSP start ceiling. The
status-bar tooltip now carries the engine version so users can
confirm at a glance which pipeline-check install is talking to the
editor. Test count: 254 → 329 (75 new) across the new and extended
suites — severity filter, code actions, preflight, version compare,
upgrade flow, status-bar tooltip, lspState.
- Per-panel severity quick-filter. New title-bar Show / Hide
Severities button opens a multi-select Quick Pick; unchecked
severities are hidden from the Findings panel only. The editor
surface (gutter, Problems panel, CodeLens) is unaffected — the
filter is for triage, not for muting the project. State persists
per workspace via
workspaceState. Composes with the existing substring filter; both are dropped when their condition clears. - Quick-fix lightbulb on every Pipeline-Check diagnostic.
Rule-agnostic actions land on every finding the lightbulb attaches
to: Open
<RULE-ID>documentation (when the server publishedDiagnostic.code.target), Copy rule ID (routes through the same code path as the panel's context-menu entry), and Show in Pipeline-Check Findings panel (always available). No CodeAction mutates the file — they're discoverability surfaces, not auto-fixes. - Fast-fail engine preflight. Before
LanguageClient.start()spawns the LSP, a 5-second probe runsimport pipeline_check; print(importlib.metadata.version(...))on the configured interpreter. A missing install fires the install toast in under a second instead of the 30-second LSP start ceiling. An out-of-date install (engine version belowMIN_ENGINE_VERSION) routes to a dedicated Upgrade in terminal CTA instead of the generic install path. The probe is gated to the defaultpython -m pipeline_check.lspshape so custom wrapper scripts skip the check (shouldPreflightreturnsfalse) and fall back to the existing start-timeout behavior. - Engine version in the status-bar tooltip. The captured version
appears as a trailing
Engine vX.Y.Zline on hover. Useful for triaging "why isn't this rule firing?" reports across people on different upstream versions. Cleared onstopClient()and on the mid-sessionState.Stoppedtransition so the tooltip stops claiming a server is connected after a crash. pipelineCheck.upgradeInTerminalcommand + welcome panel variant. New command runspython -m pip install --upgrade "pipeline-check[lsp]"in a dedicatedPipeline-Check upgradeterminal (typed but not auto-executed, matching the install-command pattern). When the preflight rejects withreason="out_of_date", the newpipelineCheck.engineOutOfDatecontext key flips, and the Findings panel switches to a third welcome entry that promotes Upgrade in terminal as its primary CTA. The toast and the panel surface the same action so a user who dismisses the toast can still find it.
- README: Install section rewritten as a numbered two-step flow
("install the Python engine, then install the extension") so
first-timers can't skip the engine. Version requirements moved
inline with each step; the standalone Requirements section is
gone. A new "Verify" step points readers at the
🛡status-bar tally and thePipeline-Check: Show language server outputcommand for the case where it doesn't appear. The Commands table was also extended to list the two new commands and the severity-toggle entry. What's newtoast copy is now generic. Previously it hard-coded the v1.0.0 surfaces (Findings panel, status bar, CodeLens, Alt+F8); the prose was stale the moment 1.0.1 shipped. The toast now saysPipeline-Check ${version} is here. See what changed?and the See release notes action does the version-specific work. One less thing to remember to update per release.
MIN_ENGINE_VERSION = "1.0.0"in src/preflight.ts is the new floor the preflight asserts. Anyone on a 0.x install sees the Upgrade in terminal CTA on next launch; every 1.0.x install passes through unchanged. The extension's stable contract with the engine — readingDiagnostic.code.target(rule-docs URL) anddata.severity(panel grouping) from publishes — has held across the 1.x line, so the floor is the same as the 1.x major. Maintainer note: bump patch/minor here when the extension starts depending on a newer field; the change forces the upgrade prompt for users behind the new floor and deserves its own CHANGELOG entry.isAtLeast/parseVersionhelpers in preflight handle the PEP 440 / SemVer shapes pipeline-check ships (numeric MAJOR.MINOR.PATCH plus occasional rc / dev tails). Pre-releases rank BELOW the corresponding release per spec, so1.2.3rc1does not satisfy aMIN_ENGINE_VERSION = "1.2.3"assertion.
Recovery republish of v1.0.2 — Open VSX returned an HTTP 405 on the v1.0.2 publish step (transient registry-side failure; v1.0.1 shipped unchanged 14 h earlier through the same code path). v1.0.2 reached the VS Code Marketplace but not Open VSX, and the "Create GitHub release" step short-circuited behind the failed publish. No source changes between v1.0.2 and v1.0.3; this tag exists solely to re-trigger the publish pipeline so Open VSX catches up with the Marketplace and the GitHub release for the 1.0.x line is restored.
- Version bump only — no functional changes. v1.0.2 is the identical extension code; users on the VS Code Marketplace will see a 1.0.2 → 1.0.3 update with no behavioural diff. Open VSX users skip 1.0.2 entirely (none was ever published there).
Bug-fix batch on top of v1.0.1 — three review rounds turned up five
real defects and a handful of housekeeping items, all covered by
nine new unit tests (245 → 254). No new features; no behaviour
change for users on the golden path. Highlights: rapid-fire LSP
restarts no longer race into a TypeError in the extension host;
Pipeline-Check: Scan Workspace failures land a real
extension-branded error instead of VS Code's generic "Command
failed" toast; scan-on-save rejections now surface in the output
channel instead of leaking as unhandled promise rejections; the
What's New upgrade-toast comparison handles double-digit
pre-release identifiers (rc.10 > rc.2); and the internal **
glob no longer matches mid-segment (a file literally named
myDockerfile is no longer classified as a Dockerfile).
- Restart-during-startup race in the LSP client no longer crashes
the extension host.
startClientreferenced the module-levelclientafter awaitingclient.start(); a concurrentstopClient(secondPipeline-Check: Restartclick, ordeactivatemid-startup) could clear the slot beforeonDidChangeStatewired up, throwingTypeError: Cannot read properties of undefined. The client is now captured into a local before the await, with an identity check after — if the slot was swapped, the orphaned LSP child is killed cleanly and no shared state is touched. Pipeline-Check: Scan Workspace/Refresh Findingsrejections surface a real toast. IffindFilesrejects before the loop starts (workspace closed mid-call, fs error),scanWorkspacere-throws; the command surface used to render that as a genericCommand 'pipelineCheck.scanWorkspace' resulted in an errortoast divorced from the click. A newrunScanCommandwrapper catches the rejection, writes ascan: failed to startline to the Pipeline-Check output channel, and shows a Pipeline-Check-brandedshowErrorMessageinstead. Per-file failures still flow through the normalformatSummarypath.scan-on-saverejections no longer leak as unhandled promise rejections.onDidSaveTextDocumentis fire-and-forget, so a rejected scan promise used to land as an "unhandled promise rejection" in the extension-host log with no connection back to the save that triggered it. The handler now catches scan failures, routes them through a new optionalonErrorhook wired to the Pipeline-Check output channel, and resolves cleanly. The busy-lock still releases on every exit path.What's Newupgrade compare now follows semver §11.4 for pre-release identifiers. The previous implementation compared pre-release suffixes lexicographically, sorc.10ranked belowrc.2(because'1' < '2'in ASCII order) — a user onrc.2upgrading torc.10would not see the upgrade toast. Numeric identifiers now compare numerically, non-numeric lexically, numeric ranks below non-numeric, and a longer identifier set wins on tie.- Internal
**/glob matcher no longer crosses segment boundaries.**translated to.*, so**/DockerfilematchedmyDockerfile(no slash before theD). ThedisabledProvidersmiddleware filter would then silence the wrong file.**/now translates to(?:.*/)?so the prefix must end on a real/(or be empty).
vscode:prepublishships with a syncedpackage-lock.json. The lockfile's top-level"version"had drifted to1.0.0whilepackage.jsonadvanced through1.0.1; this release brings both to1.0.2so thenpm cireproducibility contract the publish workflow relies on stays clean.log.setLogChannelacceptsundefined. The module already treated a missing channel as a no-op; the signature now documents that explicitly so tests (and any future caller that needs to detach) don't have to lie viaundefined as unknown as OutputChannel.
- Manifest welcome-link regex now captures dotted command IDs.
The regression-fence test that verifies every
command:pipelineCheck.Xlink in the welcome panel maps to a declared command was stopping at the first., so a future welcome edit that linked topipelineCheck.findings.refreshwould have slipped past the check. workspaceScanandnavigatetest names match what they actually test, with new sibling tests for the propagation paths. The old "withProgress throws" test only exercised the per-file caught-failure case; a new test now reaches the real pre-loopfindScannableFilesrejection path. The "strict comparison" navigate test now uses two findings so it actually verifies advancement (the old single-element setup only proved wrap-around).codeLens/findingsViewtest suites now use the fullresetStubState()reset. Closes a latent fragility where a future assertion on__stubCalls.executeCommand(populated by theFindingsTreeProviderconstructor'ssetContextcall) would have inherited stale state from earlier tests in the same file.- CodeQL workflow trimmed. Drops the GitHub template
scaffolding (
build-modematrix include,swift-vs-ubunturunner-os switch, manual-build placeholder step) so the file shows only what we actually configure — the same three languages (actions,javascript-typescript,python) and the same pinned action SHAs.
Stability batch on top of v1.0.0 — three rounds of edge-case
hardening covered by 57 new tests (194 → 251), plus supply-chain
hardening on the publish pipeline (CycloneDX SBOM + signed SLSA
provenance attached to each release). No new features; no behavior
change for users on the golden path. Highlights: the LSP install
command now uses the universal python -m pip form so the official
Windows Python installer + corporate ExecutionPolicy combo stops
blocking first-run install; the welcome panel and status bar no
longer go stale after an LSP crash or workspace-folder removal;
Scan workspace against a dead LSP surfaces a real error instead of
a false-success toast; the rc → ga "What's new" toast actually fires
this time.
- CycloneDX SBOM attached to each GitHub release. The publish
workflow now scans
package-lock.jsonviaanchore/sbom-actionand uploadspipeline-check-<version>-sbom.cdx.jsonalongside the.vsix. Downstream consumers can ingest it into their existing vuln-management tooling without re-deriving the dep set from the bundle. - Signed SLSA build provenance for each
.vsix. Emitted byactions/attest-build-provenanceusing GitHub's OIDC token and Sigstore's keyless flow. Consumers verify withgh attestation verify pipeline-check-<version>.vsix --owner greylag-ci. Covers signing (no separate cosign step) and provenance in one attestation. npm audit --omit=dev --audit-level=highgate on the publish workflow. CI already runs this on every push; the publish-side gate catches advisories that land between the merge tomainand the tag push, preventing a known-vulnerable build from shipping during the window between merge and release.
- Install command now uses
python -m pip install. Switched from the barepip installform so the install path works under two conditions that previously broke it: a corporate Windows PowerShell ExecutionPolicy that allowspython.exebut blockspip.exe, and the case wherepythonis onPATHbutpipis not (common with the official Windows Python installer when the Scripts directory wasn't added). Matches PyPA's own recommendation. README and welcome-panel copy updated.
- Status-bar relevance latch releases on folder removal. A
multi-root workspace user who removed the last CI folder used to
see the bar item pinned to "clean" for the rest of the session.
The latch now re-evaluates on
onDidChangeWorkspaceFolders: when the workspace has no CI candidate files AND no current findings, the item hides again. Re-adding a CI folder re-shows.
- Two scan-workspace runs in parallel no longer spawn two
notifications. A module-level in-flight guard collapses every
concurrent
scanWorkspacecaller to one scan. A second call (from a double-clicked button, or scan + refresh) returns immediately withskippedAsBusy: trueand, in noisy mode, surfaces a "scan already in progress" info toast. installInTerminalreuses the existing "Pipeline-Check install" terminal. Repeated clicks on the welcome-panel CTA used to stack identical terminals in the dropdown. Now the second click reuses the live terminal; an exited terminal is treated as dead and a fresh one takes its place.scan-on-saveshort-circuits when the saved file's provider is disabled. Saving a Dockerfile in a workspace that hasdockerfileinpipelineCheck.disabledProvidersused to trigger a full workspace re-open even though every published diagnostic would be dropped by the middleware. The handler now consults the livedisabledProviderssetting and skips the scan.whatsNewrc → ga transition is no longer silently swallowed. Per semver §11 a pre-release version is LOWER precedence than the corresponding release. The previous version-compare stripped the suffix and treated1.0.0-rc.1and1.0.0as equal, so pre-release testers never saw the "What's New" toast for the GA.
- Welcome panel stops lying after an LSP crash. Subscribe to
client.onDidChangeStateso a mid-session server crash (or the LanguageClient's auto-restart exhausting) flipspipelineCheck.lspReadyback tofalse. Previously the panel kept showing "Scan workspace" after the LSP died — the button still worked, it just opened files against a dead server. disabledProvidersnow silences lowercasedockerfile/jenkinsfile. The internal glob matcher inproviderForPathwas case-sensitive against**/Dockerfile, so files written in lowercase (common on Windows case-preserving filesystems) classified asundefinedand slipped past the user's disable filter.- Activation no longer hangs on a misconfigured
serverArgs.client.start()is now raced against a 30-second timeout. An emptypipelineCheck.serverArgsused to drop the Python child into the REPL where it waited on stdin forever; activation would stay half-pending and the welcome panel would never leave the install prompt. On timeout we kill the stranded subprocess and surface the same "Install in terminal / Open server log" toast the LSP-failure path uses. Scan workspaceno longer claims success against a dead LSP. The scan command now gates onisLspReady()and surfaces a warning toast with Install in terminal / Restart language server / Open server log when the LSP is down. Quiet mode (scan-on-save) stays silent. Previously the scan wouldopenTextDocumentevery candidate file, publish no diagnostics, and finish with a "scanned N files" toast even though no LSP was alive to produce findings.
First stable release. Closes the v0.x line: the Findings tree has its
remaining affordances (filter, non-preview open, scan-on-save), the
release-tooling and repo-security work is fully landed (SHAs pinned on
every action, GITHUB_TOKEN locked out of .git/config, Private
Vulnerability Reporting + Discussions enabled, production environment
gate, npm audit + dependency-review + CodeQL on every push), and the
internal eslint stack is on v9 flat config so future toolchain bumps
have a clean ramp. No telemetry — see SECURITY.md.
Pipeline-Check: Filter Findingscommand. Opens an InputBox; matches against rule ID, message body, and file path (case-insensitive substring). Re-invoking the command pre-fills the current filter so users can edit or clear (empty input clears). New$(filter)button on the Findings view title bar. The badge updates to reflect the filtered count; thelastFindingUrisset still tracks the unfiltered universe so a publish for a currently-hidden finding still wakes the tree up.Pipeline-Check: Open Findingcontext-menu entry on Findings tree leaves. Opens the finding as a permanent (non-preview) tab — useful when triaging multiple findings side-by-side. The default click-to-reveal still uses preview-style so the common "click through to scan" flow doesn't create tab clutter.- Scan-on-save mode. New
pipelineCheck.scanOnSavesetting (defaultfalse). When enabled, saving a CI/CD config file triggers a quiet workspace re-scan — the LSP already re-publishes diagnostics for the saved file itself ondidSave, so this picks up cross-file effects in other CI files that aren't currently open (a Jenkinsfile that includes the just-edited shared library, a GHA workflow that calls the just-edited composite action). Renders as a status-bar spinner with no completion toast; an in-flight guard collapses save-storms (autosave, Save All) to a single scan. (R29) - Status bar background colour reflects severity. A workspace with
any CRITICAL finding tints the bar to
statusBarItem.errorBackground(red in the default themes); a workspace with HIGH but no CRITICAL tints tostatusBarItem.warningBackground(yellow). MEDIUM / LOW / INFO keep the default fg colour so a "1 medium" workspace doesn't shout. Same ThemeColor tokens ESLint and Error Lens use, so the visual language reads correctly to any existing VS Code user. - "What's new" notification on upgrade. First activation after a version bump shows a one-time toast — "Pipeline-Check 0.X.Y is here …" — with a "See release notes" button that opens the matching GitHub release. Persists the seen-version before showing so a missed dismissal doesn't loop next launch. Suppressed when the stored version equals the manifest version (same launch).
Pipeline-Check: Scan Workspacecommand. Walks every CI/config file in the workspace (matching the same patterns the LSP'sdocumentSelectoruses), opens each viavscode.workspace.openTextDocumentso the LSP'sdidOpenpipeline picks them up, and lets the Findings panel re-render from the diagnostic stream as scans complete. Progress toast with cancellation; partial failures (read errors, unsupported encodings) are counted but don't abort the scan. Surfaced from a$(play)button on the Findings view title bar, the Command Palette, and a link in the Findings welcome state. (R10, R15)
- Quieter clipboard confirmations. Copy Rule ID and Copy LSP Install Command now write a 2-second status-bar message instead of firing a modal information toast. The copy still succeeded silently 95% of the time anyway; this confirms the action without stealing focus.
- "Refresh Findings" now triggers a real scan instead of just re-painting the tree from already-published diagnostics. Matches the user's mental model: clicking a refresh icon should fetch new data, not re-render stale data. (R10)
SCAN_PATTERNSremoved in favour ofTRIGGER_PATTERNSfromproviders.ts. The single source of truth for which files are CI-relevant now drives the documentSelector, the activationEvents, and the workspace scan — three surfaces that used to drift apart.- ESLint migrated to v9 flat config. Replaced
.eslintrc.jsonwith eslint.config.mjs; dropped@typescript-eslint/eslint-plugin+@typescript-eslint/parserin favour of the unifiedtypescript-eslintpackage. Rules carry over verbatim so lint results are unchanged. (R22)
Closes 24 of 29 items from the 2026-05-19 in-depth UX/code review.
Adds the activity-bar Findings tree's missing affordances (status bar,
CodeLens, navigation, context menus, per-provider toggles), the
release-tooling polish (production environment gate, pre-release
channel, three-OS CI, integration tests), and the discovery /
accessibility pass.
Heads-up for users with non-standard workflow paths: the
extension's activationEvents now match only the
workspaceContains: patterns shared with the LSP documentSelector
(plus onStartupFinished so the activity-bar slot is always
visible). If your repo keeps CI definitions outside the standard
locations (e.g. pipelines/build.yml instead of
.github/workflows/*.yml), the extension still activates on
onStartupFinished, but the LSP only scans files matching the
document selector. Use pipelineCheck.serverArgs to point the LSP
at a different path or symlink your custom config into a standard
location.
- Inline CodeLens summary. Each scanned file carries a
Pipeline-Check: 2 critical · 1 highlens at line 1. Click reveals the Findings panel. Re-emits on every diagnostic publish so the text tracks the latest scan. (R26) - Status bar item. Bottom-left of the window, shows the top two
non-zero severities (e.g.
$(shield) 3C 1H) with a tooltip that breaks down the full per-severity tally. Click reveals the Findings panel. (R9) - Keyboard navigation.
Alt+F8/Shift+Alt+F8jump between Pipeline-Check findings in editor order (fsPath ascending, then by line); wraps at both ends. Mirrors VS Code'sF8muscle memory for the global "Next Problem" command. (R12) - Per-provider toggles. New
pipelineCheck.disabledProviderssetting silences whole providers.dockerfilecovers bothDockerfileandContainerfile(same syntax). Useful in a monorepo where Pipeline-Check would otherwise lint a sub-project's Dockerfile that has its own lint pipeline. (R25) - Rule documentation link in leaf tooltip. When the server
publishes a
Diagnostic.code.targetURL, the Findings tree's leaf tooltip appends a clickable$(book) <rule-id> documentationlink below the message body. (R8) - Client-side structured logging. The extension's output channel
now interleaves
[client] HH:MM:SS.mmmlines around activation and command invocations with the LSP'swindow/logMessagetraffic. Easier to triage bug reports — start/ok/failed breadcrumbs land in the same surface users already focus via Show language server output. (R16) - Pre-release channel. Tags like
v0.2.0-rc.1ship to the marketplace pre-release channel; the matching GitHub release is markedprerelease. Detection is by the presence of a-after the semver core. (R24) - Right-click context menu on Findings tree leaves. Open Rule
Documentation opens the URL the server published via
Diagnostic.code.targetin the system browser; Copy Rule ID writes the rule's identifier to the clipboard. Same data the leaf tooltip already surfaces, now available without keeping the tooltip open. pipelineCheck.codeLens.enabledsetting. Defaults totrue. Hides the line-1 file-summary CodeLens for users who find it intrusive without disabling CodeLens globally. Toggle takes effect on the next render — no extension restart.pipelineCheck.copyInstallCommandcommand. Copiespip install "pipeline-check[lsp]"to the clipboard. Surfaced from the Findings welcome state and from the Command Palette so users can re-find it after dismissing the first-run error toast.
-
Welcome state of the Findings panel teaches. Now leads with what Pipeline-Check does + a Copy install command link for the Python
[lsp]extra, then onboarding ("open a workflow…"), then the Alt+F8 / Shift+Alt+F8 keyboard hint, then a---separator and the recovery actions (Restart, Open Log) demoted below. -
onStartupFinishedactivation event. The extension now wakes up after VS Code's start-up barrier so the activity-bar slot is visible in every workspace — not just ones with aworkspaceContains:match. The LSP child process still only spawns when thedocumentSelectormatches an open document, so there's no idle-Python-process cost. -
Status bar item hides in non-CI workspaces. On activation we do a one-shot
findFilesfor any of the trigger patterns; the status bar item only shows once we've seen evidence the workspace is CI-relevant (either a match or an actual diagnostic publish). Stops$(shield) cleancluttering the bottom-left in frontend projects that happen to have Pipeline-Check installed alongside other linters. -
Status bar accessibility label. Screen readers now hear "Pipeline-Check: 3 critical, 1 high" instead of the codicon shortcode + letter-by-letter abbreviation.
-
Status bar tooltip teaches Alt+F8. The trailing line of the tooltip ("Alt+F8 / Shift+Alt+F8 to step through findings") is the primary discovery surface for the navigation keybindings.
-
Command titles use title case for VS Code's convention: "Restart Language Server", "Show Language Server Output", "Refresh Findings". Existing "Go to Next Finding" and "Change Grouping" stay the same. Command IDs are unchanged — settings, keybindings, and automation continue to work.
-
@vscode/test-electronintegration suite now runs in CI (Linux only, viaxvfb-run -a). Five tests pin activation, the command-registration contract, the Findings view registration, the configuration schema completeness, and the workspace-trust capability declarations. Catches what unit tests can only approximate. (R17) -
Three-OS test matrix —
[ubuntu-latest, windows-latest, macos-latest]. The LSP child-process spawn path is Windows-sensitive; matrix CI catches the LF/CRLF and path-separator bugs single-OS CI silently misses. (R21) -
Activation surface narrowed. Triggers are
workspaceContains:patterns matching the providers we actually scan (thedocumentSelectoruses the same patterns). Opening an unrelatedpackage.jsonormkdocs.ymlno longer wakes up the extension. (H4) -
Trigger-pattern list lives in one place. Extracted into
src/providers.tsas a singlePROVIDERSmap; thedocumentSelector,activationEvents, and the LSP middleware's per-provider filter all read from it. A regression test asserts the manifest'sactivationEventsstay in lockstep with the patterns. (R14) -
Shared
vi.mock("vscode")factory undersrc/__testStubs__/. Unit tests now share a single stub instead of redefining the surface per file. (R18) -
Marketplace description length gated in CI at the 145-character truncation point so future edits don't blow it. (R20)
Restart language servertoast no longer fires on failure — if the server failed to come up, the error notification already carries the install hint; the success toast used to fire too, giving the user contradictory signals. (R2)stopClienthas a 2-second hard ceiling on the LSP child's shutdown. A deadlocked server used to hold the deactivate path indefinitely; VS Code reported "Window not responding" until the user force-quit. (R3)groupByFileno longer round-trips Uri through string for every group node. Bucket value carries the original Uri. (R4)compareByLocationsorts onfsPathinstead of the full URI string. Cross-scheme entries (file:// vs untitled://) no longer bunch at one end. (R5)collectFindingsis memoised per refresh — buildRoot and updateBadge used to walk the global diagnostic store twice per refresh. (R6)onDidChangeDiagnosticsskips refreshes from unrelated publishers. ESLint / mypy / redhat.yaml keystroke chatter no longer rebuilds the tree. The skip-check also catches clears (a stale leaf can't outlive a cleared file). (R7)
Production-readiness pass. v0.1.0 was effectively unusable on a clean install (see Fixed below); v0.1.1 is the first release that actually loads in VS Code. Also lands the Findings panel and the security hardening from the pre-marketplace review.
-
Findings panel. A dedicated activity-bar slot ("Pipeline-Check" — custom inverted-Y pipeline glyph at
media/pipeline-check.svg) carries aFindingstree that re-groups the diagnostics the LSP server has already published. Strictly a re-presentation: never triggers its own scan, so the thin-transport-adapter promise inextension.tsstays intact. The activity-bar icon carries a live count badge so "how many findings does this workspace have right now?" is answerable without expanding the panel. Three group modes — severity (default), file, rule — are switched via aChange GroupingQuick Pick that marks the active mode with$(check). Each leaf renders as the rule title plus aRULE · file:LINEdescription that drops whichever component is already implied by the parent group; clicking opens the file at the diagnostic range. CRITICAL is rendered asflameand HIGH aserrorso the two distinguish in the severity-grouped tree without breaking parity with the editor gutter (which has no "more red than red" state); INFO usescircle-outlinethemed todescriptionForegroundso it is visibly the quietest row instead of inheriting the default foreground. The welcome state leads with what the extension does rather than what is missing; the diagnostic recovery links sit on a secondary "Not seeing findings?" line. -
pipelineCheck.severityThresholdsetting. A new enum knob (low/medium/high/critical, defaultlow) that mirrors the CLI's--severity-threshold. Drives a client-sidehandleDiagnosticsmiddleware that filters out diagnostics whose upstream pipeline-check severity falls below the threshold before they reach the gutter or Problems panel, so the editor surface can be tuned independently of the CLI's report. The filter readsDiagnostic.data["severity"](set by the v1.0.6 server) so it can distinguishCRITICALfromHIGH(both map to LSPError). Diagnostics without thedata.severitymetadata pass through unconditionally, so an older server (or a non-pipeline-check publish) is never hidden.
pipelineCheck.serverCommandandpipelineCheck.serverArgsare nowmachine-overridable. Workspace overrides require an explicit prompt, so a malicious.vscode/settings.jsoncan't silently swap the interpreter or inject-c "<code>"once the user trusts the workspace.- Declared
capabilities.untrustedWorkspaces: "limited"andvirtualWorkspaces: false. The extension stays inactive in untrusted workspaces until the user trusts them, so the LSP child process never spawns from a freshly-cloned, untrusted repo. - Hardened the publish workflow. Pinned
@vscode/vsceandovsxto specific versions (no more@latestwith PATs in env), added agit merge-basecheck that refuses to publish a tag that isn't onmain, added a CHANGELOG-fold check, and narrowed workflow-level permissions tocontents: readwith the publish job opting up tocontents: write. The publish job is gated on theproductionGitHub Environment soVSCE_PAT/OVSX_PATare only readable from a run that has cleared required reviewers. - Added SECURITY.md with GitHub Private Vulnerability Reporting as the disclosure channel, response SLAs, and a published threat model.
- Vitest unit suite added. 25 tests covering the severity threshold
filter (extracted into src/severityFilter.ts)
and the Findings tree's pure logic (collection from
diagnostics, group-by-severity / file / rule, severity normalisation,
no-refresh-storm contract).
npm testruns the suite; both ci.yml and publish.yml gate on it. Test files live next to the code they cover and are stripped from the .vsix.
- The published
.vsixwas missing its runtime dependency. The previous build emittedout/extension.jsviatscbut excludednode_modules/from the package, sorequire("vscode-languageclient/node")threw on activation in a clean install. Now bundled with esbuild into a singledist/extension.js(the only JS in the.vsix); a CI smoke step (scripts/smoke.js) stubs thevscodemodule, loads the bundle, and assertsactivate/deactivateare exported so this regression class fails the build instead of the user.
-
npm audit --omit=dev --audit-level=highnow runs on every push tomainso advisories filed after a PR has merged still surface. -
Activation tightened. The extension used to activate on every YAML / JSON / Dockerfile / Terraform / Groovy file in any workspace, then rely on the server's content filter to drop unrelated documents.
activationEventsis now aworkspaceContains:list of the trigger files we actually scan (.github/workflows/*,.gitlab-ci.yml,azure-pipelines.yml, etc.). The LSP'sdocumentSelectoris switched from language IDs to matching file-path globs, so the server only sees candidate documents — no more spurious activations onpackage.json,mkdocs.yml, or a Helmvalues.yaml. -
@vscode/vsceandovsxare pinned devDependencies. Workflows invoke them via the locally-installed binaries (npx vsce,npx ovsx) afternpm ci. Versions live inpackage-lock.jsonand Dependabot's existing npm config keeps them current. -
Marketplace metadata polish. Added
Othertocategories, pointedqnaat the repo Discussions page. -
Marketplace polish pass. The
package.jsondescriptionis rewritten so the numbers that differentiate this extension (22 providers, 14 compliance frameworks beyond OWASP Top 10 CI/CD, 810+ rules) land in the first 100 characters and survive the ~145-character truncation the marketplace search results impose. Command titles renamed to Restart language server and Show language server output so the palette entries are self-disambiguating without leaning on thePipeline-Checkcategory prefix. Every configuration setting switched fromdescriptiontomarkdownDescriptionso backtick'd literals (python,python -m pipeline_check.lsp) render as code in the Settings UI rather than plain quoted text. -
README restructured for the marketplace listing. The first paragraph carries the same numbers as the marketplace description, followed by a What it scans provider table (the differentiating content that prospective users land on the listing to see). Dropped the
## Statussection (the marketplace already shows the version in the listing's metadata bar). Collapsed the architecture diagram behind a<details>block near the bottom of the page; it's a useful engineering reference but not the first scroll of a marketplace listing. -
Start-failure notification carries two actions, not one. When
python -m pipeline_check.lspfails to launch (Python missing fromPATH,[lsp]extra not installed, server crash on import), the notification now exposes Copy install command alongside Open server log. The user can act on either without re-reading the message body. Notification copy stripped of the redundantPipeline-Check:prefix that the notification chrome already shows.
First public release. Wires the editor surface to the upstream
pipeline_check.lsp
server.
- TypeScript LSP client that spawns
python -m pipeline_check.lspover stdio (vscode-languageclientv9). Document selector covers YAML, JSON, Dockerfile, Terraform, and Groovy files; the server filters further by path and content so unrelated documents are not analyzed. - Pilot provider coverage: GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, CircleCI, Google Cloud Build, Buildkite, Drone, Jenkins, and Dockerfile. Multi-file / context-heavy providers (Kubernetes, Helm, Terraform plans, live AWS, CloudFormation, SCM posture) follow in a later release.
- Three configuration knobs:
pipelineCheck.serverCommand,pipelineCheck.serverArgs, andpipelineCheck.trace.serverfor overriding the Python interpreter, module path, and LSP trace level. - Two commands under the
Pipeline-Checkcategory:- Restart server — stops the running client and respawns.
- Show server log — focuses the
Pipeline-Checkoutput channel wherewindow/logMessagetraffic lands.
- Graceful start-failure handling: when
python -m pipeline_check.lspfails (Python not onPATH,[lsp]extra not installed, server crash on import), the editor surfaces a notification with the install hint plus anOpen server logbutton. - Two F5 debug profiles in
.vscode/launch.json:- Run Extension — fresh extension-host window, no workspace.
- Run Extension (sample workflow) — opens
test-fixtures/sample-workflow/with a deliberately-vulnerable GitHub Actions workflow that fires GHA-001, GHA-004, GHA-015, and GHA-016 on open.
- VS Code 1.85+.
- Python 3.11+ with
pipeline-check[lsp]installed:pip install "pipeline-check[lsp]"