Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>10.0.1</Version>
<Version>10.0.2</Version>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<SatelliteResourceLanguages>false</SatelliteResourceLanguages>
Expand All @@ -28,4 +28,10 @@
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Templates\instructions.md" LogicalName="instructions.md" />
<EmbeddedResource Include="Templates\SKILL.md" LogicalName="SKILL.md" />
<EmbeddedResource Include="Templates\bootstrapblazor.mdc" LogicalName="bootstrapblazor.mdc" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions tools/BootstrapBlazor.LLMsDocs.Cli/CommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ private static Command BuildInstructionsCommand()

private static Command BuildInstallCommand()
{
var client = new Option<string?>("--client") { Description = "Target client: claude | cursor | all (default all)." };
var client = new Option<string?>("--client") { Description = "Target client: claude | cursor | trae | codex | all (default all)." };
var scope = new Option<string?>("--scope") { Description = "Where to write: project (cwd, default) or user (home)." };
var target = new Option<string?>("--target") { Description = "Override base directory to write into." };
var force = new Option<bool>("--force") { Description = "Overwrite existing files." };
var cmd = new Command("install", "Install agent discovery artifacts (Claude Code skill / Cursor rules).")
var cmd = new Command("install", "Install agent discovery artifacts (Claude Code skill / Cursor rules / Trae skill / Codex AGENTS.md).")
{
client, scope, target, force
};
Expand Down
30 changes: 26 additions & 4 deletions tools/BootstrapBlazor.LLMsDocs.Cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

一个轻量命令行工具,用于从 [www.blazor.zone/llms](https://www.blazor.zone/llms)
拉取 BootstrapBlazor 组件的**官方 API 文档**(参数、事件回调、公开方法、源码链接),
供 AI agent(Claude Code / Cursor 等经 Bash 调用)和开发者查询。
供 AI agent(Claude Code / Cursor / Trae / Codex 等经 Bash 调用)和开发者查询。

组件文档由官网的 `BootstrapBlazor.LLMsDocsGenerator`(生产者,CI 侧用 Roslyn 生成并发布)产出,
本工具是**消费者**:只负责按需 HTTP 拉取已生成的 `.txt` 文档并本地缓存,
Expand Down Expand Up @@ -132,24 +132,34 @@ bb-llms get Button --base-url ./wwwroot/llms
bb-llms instructions # 打印可粘贴进 CLAUDE.md / AGENTS.md 的通用片段
bb-llms install --client claude # 写 .claude/skills/bootstrapblazor/SKILL.md
bb-llms install --client cursor # 写 .cursor/rules/bootstrapblazor.mdc
bb-llms install --client all # 两者都写(默认)
bb-llms install --client trae # 写 .trae/skills/bootstrapblazor/SKILL.md
bb-llms install --client codex # 写 AGENTS.md(user scope 为 ~/.codex/AGENTS.md)
bb-llms install --client all # 四者都写(默认)
```

`install` 选项:

```
--client claude|cursor|all 目标客户端(默认 all)
--client claude|cursor|trae|codex|all 目标客户端(默认 all)
--scope project|user project=当前目录(默认),user=用户主目录
--target <dir> 覆盖写入的根目录
--force 覆盖已存在的文件(默认存在则跳过)
```

三套生态接入方式
五套生态接入方式

- **Claude Code**:`bb-llms install --client claude` 写入一个 skill,Claude Code 会根据其
`description` 在任务涉及 BootstrapBlazor 组件时**自动加载**并调用 `bb-llms`,
等效于 MCP server 的自动发现。
- **Cursor**:`bb-llms install --client cursor` 写入项目规则(匹配 `*.razor` / `*.razor.cs`)。
- **Trae**:`bb-llms install --client trae` 写入一个 skill(`.trae/skills/bootstrapblazor/SKILL.md`)。
Trae 的 skill 与 Claude 同构(同样的 `SKILL.md` + name/description frontmatter,按描述**自动匹配**),
因此复用同一套模板。
- **Codex**:`bb-llms install --client codex` 写入 `AGENTS.md`(project scope 为仓库根目录的
`AGENTS.md`,user scope 为 `~/.codex/AGENTS.md`)。Codex 没有独立的 skill/规则机制,统一读 `AGENTS.md`,
因此复用 `instructions` 的通用片段。
> ⚠️ `AGENTS.md` 是手工维护的共享文件,**默认存在则跳过**;`--force` 会整文件覆盖,原有内容会丢失。
> 已有 `AGENTS.md` 时,建议改用 `bb-llms instructions` 把片段手动粘进去。
- **通用 / 其他 agent**:把 `bb-llms instructions` 的输出粘进项目的 `CLAUDE.md` / `AGENTS.md`。

典型流程(在你的 Blazor 项目根目录):
Expand Down Expand Up @@ -180,6 +190,18 @@ dotnet tool install -g --add-source ./bin/Release BootstrapBlazor.LLMsDocs.Cli
bb-llms get Table
```

### 修改发现层模板

`instructions` / `install` 输出的模板正文是 `Templates/` 下的独立文件,**直接编辑这些文件即可**,无需改 C# 代码:

| 文件 | 对应命令 |
|---|---|
| `Templates/instructions.md` | `bb-llms instructions`(粘进 CLAUDE.md / AGENTS.md 的片段)、`bb-llms install --client codex`(写 AGENTS.md) |
| `Templates/SKILL.md` | `bb-llms install --client claude` / `--client trae`(Claude / Trae skill) |
| `Templates/bootstrapblazor.mdc` | `bb-llms install --client cursor`(Cursor 规则) |

这些文件以**嵌入资源**编入程序集(见 `.csproj`),因此全局安装后工具仍能在运行时读取到,无需依赖项目源码目录。改完重新 `dotnet build` / `dotnet pack` 即生效。

---

## 设计说明:运行时 vs 数据
Expand Down
124 changes: 53 additions & 71 deletions tools/BootstrapBlazor.LLMsDocs.Cli/Scaffolder.cs
Original file line number Diff line number Diff line change
@@ -1,87 +1,39 @@
using System.Reflection;
using System.Text;

namespace BootstrapBlazor.LLMsDocs.Cli;

/// <summary>
/// Generates the "discovery" artifacts that let AI agents know the
/// <c>bb-llms</c> CLI exists and when to use it. A plain CLI on PATH is
/// invisible to an agent unless an instruction file points at it; these
/// templates recover the auto-discovery that an MCP server would provide.
///
/// The template bodies are maintained as editable Markdown files under
/// <c>Templates/</c> and embedded into the assembly (see the .csproj), so they
/// can be edited like normal docs instead of inline C# string literals while
/// still being available to the globally-installed tool at runtime.
/// </summary>
internal static class Scaffolder
{
/// <summary>Snippet to paste into a project's CLAUDE.md / AGENTS.md.</summary>
public const string GenericSnippet = """
## BootstrapBlazor 组件文档

需要 BootstrapBlazor 组件的参数 / 事件 / 公开方法时,使用 `bb-llms` CLI 获取官方文档,不要凭记忆臆造 API:

- 查找组件名:`bb-llms search <关键词>`
- 获取组件文档:`bb-llms get <ComponentName>`(例:`bb-llms get Table`)
- 列出全部组件:`bb-llms list`

文档源默认 https://www.blazor.zone/llms ,按需联网拉取并本地缓存;可用环境变量 `BB_LLMS_BASE_URL` 或 `--base-url` 指向自建/本地源。
""";

/// <summary>Claude Code skill (.claude/skills/bootstrapblazor/SKILL.md).</summary>
public const string SkillMarkdown = """
---
name: bootstrapblazor
description: 涉及 BootstrapBlazor 组件(参数、事件回调、公开方法、用法)时使用,通过 bb-llms CLI 获取官方组件 API 文档,避免臆造参数。
---

# BootstrapBlazor 组件文档查询

当任务涉及 BootstrapBlazor 组件(编写或修改 .razor、配置组件参数、调用组件方法等)时,优先用 `bb-llms` 获取**权威**组件 API。

## 用法

1. 不确定组件名时先搜索:
```bash
bb-llms search <关键词>
```
2. 获取某组件的参数 / 事件 / 方法文档:
```bash
bb-llms get <ComponentName> # 例:bb-llms get Table
```
3. 浏览全部组件:
```bash
bb-llms list
```

输出为 Markdown(参数表、事件回调、公开方法、GitHub 源码链接)。文档源默认 https://www.blazor.zone/llms ,自动本地缓存;可用环境变量 `BB_LLMS_BASE_URL` 或 `--base-url` 指向自建/本地源。
public static string GenericSnippet => ReadTemplate("instructions.md");

## 前置条件

需已安装该工具(命令名 `bb-llms`):

```bash
dotnet tool install -g BootstrapBlazor.LLMsDocs.Cli
```
""";
/// <summary>
/// Skill manifest shared by Claude Code (.claude/skills/bootstrapblazor/SKILL.md)
/// and Trae (.trae/skills/bootstrapblazor/SKILL.md): both use the same SKILL.md
/// layout with name/description frontmatter, auto-matched by description.
/// </summary>
public static string SkillMarkdown => ReadTemplate("SKILL.md");

/// <summary>Cursor project rule (.cursor/rules/bootstrapblazor.mdc).</summary>
public const string CursorRule = """
---
description: 涉及 BootstrapBlazor 组件时,用 bb-llms CLI 获取官方组件 API 文档
globs: ["**/*.razor", "**/*.razor.cs"]
alwaysApply: false
---

# BootstrapBlazor 组件文档

编写或修改 BootstrapBlazor 组件代码时,用 `bb-llms` 获取权威组件 API,避免臆造参数:

- 搜索组件:`bb-llms search <关键词>`
- 获取文档:`bb-llms get <ComponentName>`(例:`bb-llms get Table`)
- 列出全部:`bb-llms list`

文档源默认 https://www.blazor.zone/llms ,可用 `BB_LLMS_BASE_URL` / `--base-url` 覆盖。
安装:`dotnet tool install -g BootstrapBlazor.LLMsDocs.Cli`。
""";
public static string CursorRule => ReadTemplate("bootstrapblazor.mdc");

/// <summary>Print the generic snippet to stdout.</summary>
public static int Instructions()
{
Console.WriteLine(GenericSnippet);
// The template is normalized to end with a single newline, so use Write.
Console.Write(GenericSnippet);
return 0;
}

Expand All @@ -90,10 +42,12 @@ public static int Install(string client, string scope, string? target, bool forc
{
var clients = client.ToLowerInvariant() switch
{
"all" => new[] { "claude", "cursor" },
"all" => new[] { "claude", "cursor", "trae", "codex" },
"claude" => ["claude"],
"cursor" => ["cursor"],
_ => throw new ArgumentException($"Unknown client: {client} (expected claude|cursor|all)")
"trae" => ["trae"],
"codex" => ["codex"],
_ => throw new ArgumentException($"Unknown client: {client} (expected claude|cursor|trae|codex|all)")
};

var scopeKey = scope.ToLowerInvariant();
Expand All @@ -110,9 +64,23 @@ public static int Install(string client, string scope, string? target, bool forc
var written = 0;
foreach (var c in clients)
{
var (path, content) = c == "claude"
? (Path.Combine(baseDir, ".claude", "skills", "bootstrapblazor", "SKILL.md"), SkillMarkdown)
: (Path.Combine(baseDir, ".cursor", "rules", "bootstrapblazor.mdc"), CursorRule);
var (path, content) = c switch
{
"claude" => (Path.Combine(baseDir, ".claude", "skills", "bootstrapblazor", "SKILL.md"), SkillMarkdown),
"cursor" => (Path.Combine(baseDir, ".cursor", "rules", "bootstrapblazor.mdc"), CursorRule),
// Trae skills mirror Claude skills (.trae/skills/<name>/SKILL.md, same
// name/description frontmatter, auto-matched by description), so the
// Claude skill template is reused verbatim.
"trae" => (Path.Combine(baseDir, ".trae", "skills", "bootstrapblazor", "SKILL.md"), SkillMarkdown),
// Codex has no dedicated skill/rule format — it reads AGENTS.md: the
// repo-root AGENTS.md for project scope, ~/.codex/AGENTS.md for user scope.
// It reuses the generic snippet (same content as `bb-llms instructions`).
// NOTE: AGENTS.md is a shared, hand-maintained file, so this only creates it
// when absent; --force overwrites it wholesale (existing content is lost).
_ => (scopeKey == "user"
? Path.Combine(baseDir, ".codex", "AGENTS.md")
: Path.Combine(baseDir, "AGENTS.md"), GenericSnippet)
};

if (File.Exists(path) && !force)
{
Expand All @@ -128,4 +96,18 @@ public static int Install(string client, string scope, string? target, bool forc

return written > 0 ? 0 : 1;
}

/// <summary>
/// Read an embedded template by its <c>LogicalName</c> (see the .csproj).
/// Trailing whitespace/newlines are normalized to a single trailing newline
/// so output stays stable regardless of how the source file was saved.
/// </summary>
private static string ReadTemplate(string logicalName)
{
var assembly = typeof(Scaffolder).Assembly;
using var stream = assembly.GetManifestResourceStream(logicalName)
?? throw new InvalidOperationException($"Embedded template not found: {logicalName}");
using var reader = new StreamReader(stream, Encoding.UTF8);
return reader.ReadToEnd().TrimEnd() + "\n";
}
}
35 changes: 35 additions & 0 deletions tools/BootstrapBlazor.LLMsDocs.Cli/Templates/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: bootstrapblazor
description: 涉及 BootstrapBlazor(简称 BB / bb,如“BB 组件”“bb 的 Table”“用 bb 写表格”)的组件参数、事件回调、公开方法、用法时使用,通过 bb-llms CLI 获取官方组件 API 文档,避免臆造参数。
---

# BootstrapBlazor 组件文档查询

当任务涉及 BootstrapBlazor(简称 **BB** / **bb**,下同)组件(编写或修改 .razor、配置组件参数、调用组件方法等)时,优先用 `bb-llms` 获取**权威**组件 API。

> 用户说“BB 组件”“bb 的 Table”“用 bb 写个表格”等时,BB / bb 均指 BootstrapBlazor,按本流程查询。

## 用法

1. 不确定组件名时先搜索:
```bash
bb-llms search <关键词>
```
2. 获取某组件的参数 / 事件 / 方法文档:
```bash
bb-llms get <ComponentName> # 例:bb-llms get Table
```
3. 浏览全部组件:
```bash
bb-llms list
```

输出为 Markdown(参数表、事件回调、公开方法、GitHub 源码链接)。文档源默认 https://www.blazor.zone/llms ,自动本地缓存;可用环境变量 `BB_LLMS_BASE_URL` 或 `--base-url` 指向自建/本地源。

## 前置条件

需已安装该工具(命令名 `bb-llms`):

```bash
dotnet tool install -g BootstrapBlazor.LLMsDocs.Cli
```
16 changes: 16 additions & 0 deletions tools/BootstrapBlazor.LLMsDocs.Cli/Templates/bootstrapblazor.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
description: 涉及 BootstrapBlazor(简称 BB / bb)组件时,用 bb-llms CLI 获取官方组件 API 文档
globs: ["**/*.razor", "**/*.razor.cs"]
alwaysApply: false
---

# BootstrapBlazor 组件文档

编写或修改 BootstrapBlazor(简称 BB / bb)组件代码时,用 `bb-llms` 获取权威组件 API,避免臆造参数:

- 搜索组件:`bb-llms search <关键词>`
- 获取文档:`bb-llms get <ComponentName>`(例:`bb-llms get Table`)
- 列出全部:`bb-llms list`

文档源默认 https://www.blazor.zone/llms ,可用 `BB_LLMS_BASE_URL` / `--base-url` 覆盖。
安装:`dotnet tool install -g BootstrapBlazor.LLMsDocs.Cli`。
9 changes: 9 additions & 0 deletions tools/BootstrapBlazor.LLMsDocs.Cli/Templates/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## BootstrapBlazor 组件文档

需要 BootstrapBlazor(简称 BB / bb)组件的参数 / 事件 / 公开方法时,使用 `bb-llms` CLI 获取官方文档,不要凭记忆臆造 API:

- 查找组件名:`bb-llms search <关键词>`
- 获取组件文档:`bb-llms get <ComponentName>`(例:`bb-llms get Table`)
- 列出全部组件:`bb-llms list`

文档源默认 https://www.blazor.zone/llms ,按需联网拉取并本地缓存;可用环境变量 `BB_LLMS_BASE_URL` 或 `--base-url` 指向自建/本地源。
Loading