Skip to content

feat(LLMsDocsCli): support Extensions components - #1271

Merged
ArgoZhang merged 8 commits into
masterfrom
dev-llms-cli
Oct 30, 2026
Merged

ArgoZhang merged 8 commits into
masterfrom
dev-llms-cli

Conversation

@ArgoZhang

@ArgoZhang ArgoZhang commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Link issues

fixes #1270

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Extend the LLMs Docs CLI to resolve, list, search, and retrieve components from both core and extension documentation indexes.

New Features:

  • Add support for discovering and retrieving BootstrapBlazor.Extensions components and shared services through the LLMs Docs CLI.

Bug Fixes:

  • Report specific index and document lookup failures instead of treating all missing files as unknown components.

Enhancements:

  • Deduplicate search results by document path while preserving package-specific entries in listings.
  • Update CLI usage guidance to cover extension components, shared services, caching, and local verification.

Documentation:

  • Document extension component and service support, lookup behavior, cache refresh requirements, and local regression verification.

@sourcery-ai

sourcery-ai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The CLI now discovers component and extension documents from llms.txt, carries document metadata through list/search results, fetches the indexed path for get, and documents the new extension/service behavior and verification workflow.

Sequence diagram for indexed component and extension retrieval

sequenceDiagram
    participant User
    participant CLI
    participant LlmsDocsClient
    participant llms_txt
    participant Document

    User->>CLI: get SelectCity
    CLI->>LlmsDocsClient: GetComponentAsync(name)
    LlmsDocsClient->>llms_txt: GetIndexAsync()
    llms_txt-->>LlmsDocsClient: llms.txt
    LlmsDocsClient->>LlmsDocsClient: ParseIndex(indexText)
    LlmsDocsClient->>Document: FetchAsync(entry.DocumentPath)
    Document-->>LlmsDocsClient: extension document
    LlmsDocsClient-->>CLI: document text
    CLI-->>User: output document
Loading

Flow diagram for extension-aware search results

flowchart LR
    Index["llms.txt"] --> Parse["ParseIndex(indexText)"]
    Parse --> Entries["ComponentEntry"]
    Entries --> Metadata["IsExtension + DocumentPath"]
    Metadata --> Search["SearchAsync(query, limit)"]
    Search --> Deduplicate["DistinctBy(DocumentPath)"]
    Deduplicate --> Results["JSON or text results"]
Loading

File-Level Changes

Change Details Files
Resolve component documents through the published index instead of assuming the core components directory.
  • Make get load and parse llms.txt before resolving a case-insensitive component name.
  • Fetch the path recorded by the index and report the specific missing-index reason.
  • Support local sources that contain the index and document paths.
tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs
tools/BootstrapBlazor.LLMsDocs.Cli/CommandFactory.cs
Extend index parsing and structured results to represent extension components and shared documents.
  • Accept components/ and extensions/ document links.
  • Track whether an entry is an extension and retain its document path.
  • Deduplicate search results by document path before applying the limit while preserving list entries.
tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs
tools/BootstrapBlazor.LLMsDocs.Cli/Models.cs
Update CLI documentation and verification guidance for extension-aware behavior.
  • Document extension and service discovery, path-based deduplication, cache refresh behavior, and failure semantics.
  • Add SelectCity and shared-service examples.
  • Add the PowerShell client verification command and update local source path guidance.
tools/BootstrapBlazor.LLMsDocs.Cli/README.md
Adjust CLI project configuration for the extension-support implementation.
  • Update project configuration and package/build metadata.
tools/BootstrapBlazor.LLMsDocs.Cli/BootstrapBlazor.LLMsDocs.Cli.csproj

Assessment against linked issues

Issue Objective Addressed Explanation
#1270 Bump the LLMs Docs CLI version to 10.0.5. ✅
#1270 Support BootstrapBlazor.Extensions components in the CLI, including discovering them from the index and retrieving their documentation. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@bb-auto bb-auto Bot added the enhancement New feature or request label Oct 30, 2026
@bb-auto bb-auto Bot added this to the v10.0.0 milestone Oct 30, 2026

@bb-auto bb-auto Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto approved by bb-auto

@ArgoZhang
ArgoZhang merged commit cae0629 into master Oct 30, 2026
3 checks passed
@ArgoZhang
ArgoZhang deleted the dev-llms-cli branch October 30, 2026 04:18

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 5 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs" line_range="169" />
<code_context>
-    // Matches: "- [Button](components/Button.txt) - optional description"
-    [GeneratedRegex(@"^- \[(?<name>[^\]]+)\]\(components/[^)]+\.txt\)(?:\s*-\s*(?<desc>.*))?$")]
+    // Matches component and extension links in llms.txt.
+    [GeneratedRegex(@"^- \[(?<name>[^\]]+)\]\((?<path>(?:components|extensions)/[^)]+\.txt)\)(?:\s*-\s*(?<desc>.*))?$")]
     private static partial Regex IndexLineRegex();

</code_context>
<issue_to_address>
**Untrusted paths escape documentation roots**

When an untrusted index contains a traversal path and a caller requests that entry, `ParseIndex` accepts the path and `GetComponentAsync` passes it to `FetchAsync` without containment checks, so local reads escape `_baseDir` and remote caching writes outside `_cacheRoot`, exposing or overwriting local files.

Reject traversal paths and verify resolved read and cache paths stay inside their configured roots before accessing them.

Also at `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs:203`.
</issue_to_address>

### Comment 2
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/CommandFactory.cs" line_range="134" />
<code_context>
+            catch (FileNotFoundException ex)
             {
-                Console.Error.WriteLine($"error: component '{name}' not found. Try: bb-llms search <keyword>");
+                Console.Error.WriteLine($"error: {ex.Message} Try: bb-llms search <keyword>");
                 return 1;
             }
</code_context>
<issue_to_address>
**Lookup errors expose source details**

When a requested document is missing and the configured source path or URL contains sensitive information, `BuildGetCommand` prints the exception message verbatim; `FetchAsync` includes the full local path or request URL in missing-document exceptions, so stderr and captured agent or CI logs expose private paths or secret-bearing source URLs.

Print a generic missing-document message in the normal error path and expose detailed diagnostics only through an explicitly enabled, redacted debug mode.
</issue_to_address>

### Comment 3
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs" line_range="80" />
<code_context>
+            throw new FileNotFoundException($"Component not found in index: {name}");
+        }
+
+        return await FetchAsync(entry.DocumentPath, ct);
     }

</code_context>
<issue_to_address>
**Concurrent reads return partial documents**

When one CLI invocation refreshes a remote document while another invocation reads the same cached path, `FetchAsync` writes refreshed cache content directly to the shared file before updating its metadata; another CLI invocation can read that file while it is truncated or partially written and return incomplete documentation.

Write cache content to a temporary file and atomically replace the cache file, coordinating metadata updates so readers cannot observe an in-progress refresh.
</issue_to_address>

### Comment 4
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs" line_range="74" />
<code_context>

-        return FetchAsync($"components/{name}.txt", ct);
+        var entry = ParseIndex(await GetIndexAsync(ct))
+            .FirstOrDefault(e => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase));
+        if (entry is null)
+        {
</code_context>
<issue_to_address>
**Extension documents become inaccessible**

When the index contains core and extension entries with the same name, `GetComponentAsync` uses `FirstOrDefault` to select the first matching name, and core entries precede extension entries, so `get` always fetches the core document and provides no way to retrieve the extension document.

Provide a way to disambiguate matching names so callers can select the extension document.
</issue_to_address>

### Comment 5
<location path="tools/BootstrapBlazor.LLMsDocs.Cli/README.md" line_range="196" />
<code_context>
+在 Extentions 仓库根目录执行 CLI 回归检查:
+
+```powershell
+.\tools\BootstrapBlazor.LLMsDocs.Cli\tests\Verify-Client.ps1
+```
+
</code_context>
<issue_to_address>
**Documented verification script is missing**

When a maintainer follows the documented local regression-check command, the README directs maintainers to run `tests/Verify-Client.ps1`, but the CLI directory contains no such PowerShell script, so the documented regression check fails before exercising the client.

Add the referenced verification script or change the README to point to an existing test command.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

// Matches: "- [Button](components/Button.txt) - optional description"
[GeneratedRegex(@"^- \[(?<name>[^\]]+)\]\(components/[^)]+\.txt\)(?:\s*-\s*(?<desc>.*))?$")]
// Matches component and extension links in llms.txt.
[GeneratedRegex(@"^- \[(?<name>[^\]]+)\]\((?<path>(?:components|extensions)/[^)]+\.txt)\)(?:\s*-\s*(?<desc>.*))?$")]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Untrusted paths escape documentation roots

When an untrusted index contains a traversal path and a caller requests that entry, ParseIndex accepts the path and GetComponentAsync passes it to FetchAsync without containment checks, so local reads escape _baseDir and remote caching writes outside _cacheRoot, exposing or overwriting local files.

Reject traversal paths and verify resolved read and cache paths stay inside their configured roots before accessing them.

Also at tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs:203.

Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs` at line 169:

**Untrusted paths escape documentation roots**

When an untrusted index contains a traversal path and a caller requests that entry, `ParseIndex` accepts the path and `GetComponentAsync` passes it to `FetchAsync` without containment checks, so local reads escape `_baseDir` and remote caching writes outside `_cacheRoot`, exposing or overwriting local files.

Reject traversal paths and verify resolved read and cache paths stay inside their configured roots before accessing them.

Also at `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs:203`.

catch (FileNotFoundException ex)
{
Console.Error.WriteLine($"error: component '{name}' not found. Try: bb-llms search <keyword>");
Console.Error.WriteLine($"error: {ex.Message} Try: bb-llms search <keyword>");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Lookup errors expose source details

When a requested document is missing and the configured source path or URL contains sensitive information, BuildGetCommand prints the exception message verbatim; FetchAsync includes the full local path or request URL in missing-document exceptions, so stderr and captured agent or CI logs expose private paths or secret-bearing source URLs.

Print a generic missing-document message in the normal error path and expose detailed diagnostics only through an explicitly enabled, redacted debug mode.

Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/CommandFactory.cs` at line 134:

**Lookup errors expose source details**

When a requested document is missing and the configured source path or URL contains sensitive information, `BuildGetCommand` prints the exception message verbatim; `FetchAsync` includes the full local path or request URL in missing-document exceptions, so stderr and captured agent or CI logs expose private paths or secret-bearing source URLs.

Print a generic missing-document message in the normal error path and expose detailed diagnostics only through an explicitly enabled, redacted debug mode.

throw new FileNotFoundException($"Component not found in index: {name}");
}

return await FetchAsync(entry.DocumentPath, ct);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Concurrent reads return partial documents

When one CLI invocation refreshes a remote document while another invocation reads the same cached path, FetchAsync writes refreshed cache content directly to the shared file before updating its metadata; another CLI invocation can read that file while it is truncated or partially written and return incomplete documentation.

Write cache content to a temporary file and atomically replace the cache file, coordinating metadata updates so readers cannot observe an in-progress refresh.

Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs` at line 80:

**Concurrent reads return partial documents**

When one CLI invocation refreshes a remote document while another invocation reads the same cached path, `FetchAsync` writes refreshed cache content directly to the shared file before updating its metadata; another CLI invocation can read that file while it is truncated or partially written and return incomplete documentation.

Write cache content to a temporary file and atomically replace the cache file, coordinating metadata updates so readers cannot observe an in-progress refresh.


return FetchAsync($"components/{name}.txt", ct);
var entry = ParseIndex(await GetIndexAsync(ct))
.FirstOrDefault(e => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Extension documents become inaccessible

When the index contains core and extension entries with the same name, GetComponentAsync uses FirstOrDefault to select the first matching name, and core entries precede extension entries, so get always fetches the core document and provides no way to retrieve the extension document.

Provide a way to disambiguate matching names so callers can select the extension document.

Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/Services/LlmsDocsClient.cs` at line 74:

**Extension documents become inaccessible**

When the index contains core and extension entries with the same name, `GetComponentAsync` uses `FirstOrDefault` to select the first matching name, and core entries precede extension entries, so `get` always fetches the core document and provides no way to retrieve the extension document.

Provide a way to disambiguate matching names so callers can select the extension document.

在 Extentions 仓库根目录执行 CLI 回归检查:

```powershell
.\tools\BootstrapBlazor.LLMsDocs.Cli\tests\Verify-Client.ps1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ Low · Documented verification script is missing

When a maintainer follows the documented local regression-check command, the README directs maintainers to run tests/Verify-Client.ps1, but the CLI directory contains no such PowerShell script, so the documented regression check fails before exercising the client.

Add the referenced verification script or change the README to point to an existing test command.

Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocs.Cli/README.md` at line 196:

**Documented verification script is missing**

When a maintainer follows the documented local regression-check command, the README directs maintainers to run `tests/Verify-Client.ps1`, but the CLI directory contains no such PowerShell script, so the documented regression check fails before exercising the client.

Add the referenced verification script or change the README to point to an existing test command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(LLMsDocsCli): support Extensions components

1 participant