ai-docs-inventory

$npx mdskill add MicrosoftDocs/windows-driver-docs-ddi/ai-docs-inventory

Inventory and classify APIs from CSV for documentation generation.

  • Cross-references API filenames against existing docs and stubs.
  • Integrates with Azure DevOps REST API for data retrieval.
  • Classifies status based on content presence in specified repos.
  • Outputs finalized CSV ready for the documentation generation tool.
SKILL.md
.github/skills/ai-docs-inventoryView on GitHub ↗
---
name: ai-docs-inventory
description: 'Inventory and classify APIs listed in a pre-provided CSV for a WDK header file. Use when: inventorying a header, classifying APIs, validating a CSV for doc generation, checking what needs to be documented.'
argument-hint: 'Specify a header name (e.g. soundwireclass) and the path to the CSV file.'
---

# Inventory Header

Read a pre-provided CSV of target API filenames, cross-reference each entry against existing docs, stubs, and published content via the ADO REST API, classify their status, and finalize the CSV for use with the `ai-docs-generate` skill.

**No local repo clones required.** All repo interactions use the Azure DevOps REST API.

## Parameters

| Parameter | Value |
|-----------|-------|
| ADO Org | `https://dev.azure.com/cpubwin` |
| ADO Project | `drivers` |
| Docs Repo | `wdk-ddi` (branches: `main`, `stubs/main`) |
| Published Docs Repo | `wdk-ddi-build` (branch: `live`) |
| Content Path | `wdk-ddi-src/content/{header}/` |
| Stubs Branch | `stubs/main` (default; user may specify alternate like `stubs/release-amethyst`) |
| Header Name | Provided by the user (e.g. `soundwireclass`) |
| CSV Input | Provided by the user at any local path (e.g. `D:\work\soundwireclass.csv`) |
| Working Directory | Derived from CSV path (parent folder of the CSV file) |

## Prerequisites

- The user provides a header name and a path to a CSV file. **That is the only user requirement.**
- Azure CLI (`az`) should be available for auth token acquisition. If not, the agent will prompt for an ADO Personal Access Token (PAT) once per session.

## File Naming Conventions

Map each API entity to a filename using these prefixes:

| Prefix | Type | Example |
|--------|------|---------|
| `nf` | Function | `nf-soundwireclass-somefunc.md` |
| `ns` | Structure | `ns-soundwireclass-some_struct.md` |
| `ne` | Enumeration | `ne-soundwireclass-some_enum.md` |
| `nc` | Callback | `nc-soundwireclass-evt_some_callback.md` |
| `ni` | IOCTL | `ni-soundwireclass-ioctl_some_code.md` |
| `nn` | Interface | `nn-soundwireclass-isome_interface.md` |
| `nl` | Class | `nl-soundwireclass-some_class.md` |

The filename pattern is: `{prefix}-{header}-{api_name_lowercase}.md`

Where `{header}` is the header name without the `.h` extension.

### Header Landing Page

On the stubs branch, the header landing page is always named `na-{header}.md`. When it is copied to `wdk-ddi-src/content/{header}/` on the `main` branch, it is renamed to `index.md`. In the published docs repo, it also appears as `index.md`. When cross-referencing, check for `na-{header}.md` on the stubs branch and `index.md` on `main` and in the published docs repo.

### Legacy Filename Exceptions

Some existing files in the published docs repo or on `main` may have non-standard filenames (e.g. an extra underscore like `ns-header-_struct_name.md` instead of `ns-header-struct_name.md`). These are historical naming errors. **Do not rename existing files** — doing so would break published links. When cross-referencing, also check for these variant filenames. For **new** APIs, always use the approved naming convention.

## Execution Strategy

**Write all PowerShell logic into a single self-contained `.ps1` script file, then execute it in one terminal call.** Do NOT run ADO REST calls or variable assignments as separate interactive terminal commands — PowerShell variables are lost between terminal invocations and long-running commands may time out and get moved to the background, breaking the workflow.

The pattern is:
1. Create a script file at `{workingDir}\inventory.ps1` containing all the logic from the Procedure below.
2. Execute it in a single terminal call: `powershell -ExecutionPolicy Bypass -File "{workingDir}\inventory.ps1"`
3. Parse the script's console output to present results to the user.

The script should accept no parameters — hardcode the `{header}`, `{csvPath}`, and `{workingDir}` values directly into the generated script.

## Procedure

Write a single `inventory.ps1` script that performs all of the following steps, then execute it.

1. Strip the `.h` extension from the user-provided header name to get `{header}` (e.g. `soundwireclass.h` → `soundwireclass`).

2. **Resolve paths.** The user provides a CSV path. Derive the working directory from it. The script should validate the CSV exists and read it:

   ```powershell
   $ErrorActionPreference = "Stop"
   $header = "{header}"
   $csvPath = "{user-provided CSV path}"
   $workingDir = Split-Path $csvPath -Parent

   if (-not (Test-Path $csvPath)) {
       Write-Error "CSV not found at $csvPath."
       exit 1
   }
   ```

   Read the CSV:
   ```powershell
   $csvData = Import-Csv $csvPath
   ```

   The CSV has a header row. Look for a column containing file paths (commonly `FilePath` or `filename`) with values like `wdk-ddi-src/content/{header}/{filename}.md`. Filter to rows with valid `.md` paths.

3. **Obtain ADO auth token.** Try Azure CLI first, then fail with a clear message (PAT prompting cannot work inside a non-interactive script):

   ```powershell
   $token = (az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv 2>$null)
   if (-not $token) {
       Write-Error "Failed to get ADO token. Run 'az login' first, or set `$env:ADO_PAT before running."
       exit 1
   }
   $h = @{ Authorization = "Bearer $token" }
   $adoBase = "https://dev.azure.com/cpubwin/drivers/_apis/git/repositories"
   ```

4. For each entry in the CSV, extract the target filename from the path (e.g. `wdk-ddi-src/content/{header}/nf-soundwireclass-somefunc.md` → `nf-soundwireclass-somefunc.md`).

5. **List all files in the directory on each branch** (one API call per branch, not per file). This detects legacy filename variants (see [Legacy Filename Exceptions](#legacy-filename-exceptions)):

   ```powershell
   # List files on main branch of wdk-ddi
   try {
       $r1 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
       $mainFiles = @($r1.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
   } catch { $mainFiles = @() }

   # List files on stubs branch of wdk-ddi
   try {
       $r2 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=stubs/main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
       $stubFiles = @($r2.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
   } catch { $stubFiles = @() }

   # List files on live branch of wdk-ddi-build (published docs)
   try {
       $r3 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi-build/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=live&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
       $pubFiles = @($r3.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
   } catch { $pubFiles = @() }

   Write-Host "Main: $($mainFiles.Count) files, Stubs: $($stubFiles.Count) files, Published: $($pubFiles.Count) files"
   ```

   Compare each expected filename against the directory listings. If a file exists with a minor variant (e.g. `ns-header-_struct_name.md` instead of `ns-header-struct_name.md`), treat it as a match — the doc exists under the legacy name. **Use the legacy filename in the CSV** (do not rename it).

   a. Check if the file exists on `main` of `wdk-ddi` (look for the filename in `$mainFiles`).

   b. Check if a stub exists on the stubs branch (look for the filename in `$stubFiles`).

   c. Check if the file exists on `live` of the published docs repo `wdk-ddi-build` (look for the filename in `$pubFiles`).

6. Classify each API into one of three categories:
   - **new**: Stub exists on `stubs/main` but no completed doc on `main`
   - **update**: File already exists on `main` — needs to be compared with the latest stub to identify changes
   - **stub not found**: No stub and no existing doc

7. **Output grouped results** to the console for the agent to parse and present:

   ```
   === New (ready to document) ===
   nf-soundwireclass-somefunc.md          (function)
   ns-soundwireclass-some_struct.md       (structure)

   === Update (existing doc, needs diff) ===
   nf-soundwireclass-otherfunc.md         (function)  [+2 params, -1 param, ~1 param]

   === Stub not found ===
   ne-soundwireclass-some_enum.md         (enumeration)
   ```

8. **Diff existing docs against stubs.** For each "update" entry, fetch the existing doc from `main` and the latest stub from `stubs/main` via the ADO REST API. Compare the parameter/field/value sections to identify:
   - **Added** parameters, fields, or enum values (present in stub but not in existing doc)
   - **Removed** parameters, fields, or enum values (present in existing doc but not in stub)
   - **Modified** parameters, fields, or enum values (present in both but with different types or descriptions)

   Output a per-file change summary (e.g. `[+2 params, -1 param, ~1 param]`) in the console results.

9. **Write the updated CSV** at the original CSV path. The format must be compatible with the `ai-docs-generate` skill:

   ```csv
   filename,status
   wdk-ddi-src/content/{header}/{filename1}.md,new
   wdk-ddi-src/content/{header}/{filename2}.md,update
   ```

   The script writes both "new" and "update" entries. "Stub not found" entries are excluded.

10. **Output a summary** to the console:
    - Number of APIs in the CSV by type
    - Number selected for documentation
    - Working directory: `{workingDir}`
    - CSV file location: `{csvPath}`

After the script finishes, the agent should:

11. Open the CSV in the editor:

    ```powershell
    code $csvPath
    ```

12. **Continue or stop.** Ask the user:

    > Inventory complete. Press **y** to continue to generate API docs, or type **n** to stop.

    - If the user types **y**: automatically invoke the `ai-docs-generate` skill, passing the same header name and CSV path. Behave as if the user typed `/ai-docs-generate {header}.h {workingDir}`.
    - If the user types **n**: stop and tell them they can run it later with: `/ai-docs-generate {header}.h {workingDir}`

    > **Tip:** To run all three steps (inventory → generate → submit) with no interaction, use the `ai-docs-autopilot` skill instead.

More from MicrosoftDocs/windows-driver-docs-ddi