Repository navigation
feat(LLMsDocsCli): support Extensions components - #1271
Conversation
Reviewer's GuideThe 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 retrievalsequenceDiagram
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
Flow diagram for extension-aware search resultsflowchart 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"]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
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>| // 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>.*))?$")] |
There was a problem hiding this comment.
🟠 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>"); |
There was a problem hiding this comment.
🟡 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); |
There was a problem hiding this comment.
🟡 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)); |
There was a problem hiding this comment.
🟡 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 |
There was a problem hiding this comment.
⚪ 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.
Link issues
fixes #1270
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Extend the LLMs Docs CLI to resolve, list, search, and retrieve components from both core and extension documentation indexes.
New Features:
Bug Fixes:
Enhancements:
Documentation: