Add az-Find-AzDevOpsText fuzzy search over cached hierarchy#153
Add az-Find-AzDevOpsText fuzzy search over cached hierarchy#153jdschleicher wants to merge 3 commits into
Conversation
Adds az-Find-AzDevOpsText: a quick free-text filter over every work item in the cached hierarchy (Epics, Features, requirement-tier), searching Title + Description. A query splits into whitespace tokens that must all match (case-insensitive substring); with no query the full hierarchy goes into Out-ConsoleGridView so its own live-filter box searches Title + Description. Selecting a row reuses the shared open/create-child action like the other az-Show-* views. To make descriptions searchable: - add [System.Description] to the three seeded hierarchy WIQLs - cache a cleaned, HTML-stripped Description on each hierarchy item (new ConvertFrom-AzDevOpsHtmlText helper + converter field) Existing users with older seeded *.wiql files get a one-line tip to add [System.Description] and re-sync; Title-only search works until they do. Wired into az-help and the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AQoEMfuDKdoS5DKTcAcXUu
🐚 Senior Bash EngineerSummaryNo bash files changed in this PR. The true diff scope ( Findings
Sourcing Wire-UpN/A — no new files under Naming ConventionN/A — no bash aliases/functions added or changed VerdictAPPROVE — no bash files in this diff Generated by Claude Code |
🛡️ Senior Security EngineerStatic review (pwsh unavailable) of the diff on Focus-area findings1. WIQL injection via 2. ReDoS in 3. Decoded HTML execution — NOT VULNERABLE. 4. Search haystack — confirmed inert. 5. Browser-open sink — safe. 6. Secrets / network / file writes — none introduced. VerdictNo security issues found in this diff. The VERDICT: PASS Generated by Claude Code |
💠 Senior PowerShell EngineerSummaryReviewed the PR diff ( Findings
Automatic-Variable Shadow AuditPASS. The ConvertFrom-AzDevOpsHtmlText CorrectnessPASS. The pipeline is sound for best-effort display/search normalization (and the comment explicitly scopes it as such, not a full parser):
Minor note (no action): Parameter BindingPASS. Every cross-function call binds to a real parameter:
Output Streams (Write-Host vs Write-Output)PASS. All three Error HandlingPASS / N/A. The command reads only the local hierarchy JSON cache via Profile Side EffectsPASS. Every top-level addition is a Approved VerbsPASS.
Naming / Style (CLAUDE.md mandates)PASS. Every Dot-Sourcing Wire-UpN/A — no new VerdictAPPROVE — no blocking issues. Two LOW/informational notes only. pwsh was unavailable in the review environment; parse-correctness was assessed by close reading against the established in-repo patterns rather than by running the parser. Recommend the author run Generated by Claude Code |
🧼 Senior Clean-Code EngineerSummaryFive PowerShell files changed, all in the Azure DevOps surface. The new Findings
CLAUDE.md rule checks (the ones called out)
Duplication Map
Function Sizes
VerdictREQUEST CHANGES — 1 HIGH finding (named CLAUDE.md extract-repeated-branches violation: the Generated by Claude Code |
Addresses the clean-code review on PR #153: the closed-state filter block was inlined in both az-Find-AzDevOpsText and az-Find-AzDevOpsWorkItem. Lift it into one private helper both call, per CLAUDE.md's extract-repeated-branches rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AQoEMfuDKdoS5DKTcAcXUu
…ep map Sync the diagram doc with the new free-text search surface: the public az-Find-AzDevOpsText node (architecture + dependency map), its helpers (Get-AzDevOpsVisibleItems, Select-AzDevOpsTextMatches, Format-AzDevOpsTextSnippet, Write-AzDevOpsNoDescriptionTip), the new ConvertFrom-AzDevOpsHtmlText normalizer off ConvertFrom-AzDevOpsHierarchyItem, and route the existing az-Find-AzDevOpsWorkItem closed-state filter through the shared Get-AzDevOpsVisibleItems helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AQoEMfuDKdoS5DKTcAcXUu
Contents
4727cae(was REQUEST CHANGES) — View341ecffHow it works
az-Find-AzDevOpsTextreads the existing cached hierarchy (now carrying an HTML-strippedDescriptionper item), applies the shared-IncludeClosedgate, then filters by an all-tokens-must-match search over Title + Description. Hits are projected (with a truncated Description snippet) intoOut-ConsoleGridView, whose own live filter narrows further; selecting a row hands off to the standard open / create-child action.flowchart TD Entry(["az-Find-AzDevOpsText<br/>[query] [-IncludeClosed]"]):::pub Read[Read-AzDevOpsHierarchyCache]:::priv Hier[(hierarchy.json)]:::io Conv[ConvertFrom-AzDevOpsHierarchyItem]:::priv Html[ConvertFrom-AzDevOpsHtmlText<br/>strip HTML to plain Description]:::priv Tip[Write-AzDevOpsNoDescriptionTip]:::priv Visible[Get-AzDevOpsVisibleItems<br/>-IncludeClosed gate]:::priv Match[Select-AzDevOpsTextMatches<br/>all tokens in Title+Description]:::priv Empty{matches?} NoHits([print no-matches, return]):::priv Snip[Format-AzDevOpsTextSnippet<br/>Description column]:::priv Grid[Show-AzDevOpsRows -PassThru<br/>Out-ConsoleGridView live filter]:::priv Action[Invoke-AzDevOpsRowAction<br/>open / create child]:::priv Entry --> Read --> Hier Read --> Conv --> Html Entry --> Tip Entry --> Visible --> Match --> Empty Empty -- no --> NoHits Empty -- yes --> Snip --> Grid --> Action classDef pub fill:#1f3a5f,stroke:#4ea3ff,color:#fff classDef priv fill:#3a3a3a,stroke:#999,color:#fff classDef io fill:#5a4a1a,stroke:#e0c060,color:#fffSummary
Adds
az-Find-AzDevOpsText— a quick free-text/fuzzy filter over every work item in the cached hierarchy (Epics, Features, and the requirement tier: User Story / PBI / Requirement / Issue), searching Title + Description.az-Find-AzDevOpsText "deploy pipeline"— the query splits into whitespace tokens; an item matches when all tokens appear (case-insensitive substring) in its Title or Description. Hits render inOut-ConsoleGridView.az-Find-AzDevOpsText(no query) — dumps the whole hierarchy into the grid so its own live-filter box searches Title + Description as you type.az-Find-AzDevOpsText -IncludeClosed auth— include Closed/Removed items.az-Show-*views.Issue
No tracked issue — direct feature request via
/next-task.Changes
powcuts_by_cli/azdevops_find.ps1— new publicaz-Find-AzDevOpsText+ private helpersSelect-AzDevOpsTextMatches,Format-AzDevOpsTextSnippet,Write-AzDevOpsNoDescriptionTip, and the sharedGet-AzDevOpsVisibleItems-IncludeClosedgate (now also used byaz-Find-AzDevOpsWorkItem).powcuts_by_cli/azdevops_views.ps1— newConvertFrom-AzDevOpsHtmlText(strips HTML from descriptions);Descriptionfield added toConvertFrom-AzDevOpsHierarchyItem.powcuts_by_cli/azdevops_paths.ps1—[System.Description]added to the three seeded hierarchy WIQLs (epics / features / user-stories).powcuts_by_cli/azdevops_help.ps1—az-helpcatalog entry (DailyRead).powcuts_by_cli/azdevops_auth.ps1+README.md— verb matrix + usage docs.docs/azure-devops-diagrams.md— architecture + dependency-map nodes/edges for the new surface.PowerShell-only — the AzDevOps surface has no bash counterpart.
Existing-user note
Description search needs
[System.Description]in the hierarchy WIQLs. It now ships in the seeded defaults, but users whose*.wiqlfiles were seeded earlier must runaz-Open-HierarchyWiqls, add[System.Description]to eachSELECT, and re-runaz-Sync-AzDevOpsCache. The command prints a one-line tip when it notices no descriptions are cached. Title-only search works regardless.Test Plan
az-Find-AzDevOpsText+ tab-tab autocompletes under theaz-Find-prefixaz-Sync-AzDevOpsCachethenaz-Find-AzDevOpsText— grid opens with the full hierarchy + a Description column; the filter box narrows liveaz-Find-AzDevOpsText "<word in a title>"— only matching items show; picking one fires the open/create-child prompt[System.Description]to the WIQLs + re-sync — a word found only in a description matches🤖 Generated with Claude Code
https://claude.ai/code/session_01AQoEMfuDKdoS5DKTcAcXUu