diff --git a/.github/agents/community-toolkit-integration-doc-writer.agent.md b/.github/agents/community-toolkit-integration-doc-writer.agent.md index 44ba27988..ab1a52b26 100644 --- a/.github/agents/community-toolkit-integration-doc-writer.agent.md +++ b/.github/agents/community-toolkit-integration-doc-writer.agent.md @@ -1,6 +1,19 @@ --- -description: 'Turns a README from a Community Toolkit integration into a docs page in the repo.' -tools: ['read/terminalSelection', 'read/terminalLastCommand', 'read/getNotebookSummary', 'read/problems', 'read/readFile', 'edit/createDirectory', 'edit/createFile', 'edit/editFiles', 'search', 'web', 'todo'] +description: "Turns a README from a Community Toolkit integration into a docs page in the repo." +tools: + [ + "read/terminalSelection", + "read/terminalLastCommand", + "read/getNotebookSummary", + "read/problems", + "read/readFile", + "edit/createDirectory", + "edit/createFile", + "edit/editFiles", + "search", + "web", + "todo", + ] name: Community Toolkit Integration Doc Writer --- @@ -10,41 +23,41 @@ Documentation should match the style and format of existing documentation in the ## Repo structure -* Documentation will be created in the `src/frontend/src/content/docs/integrations` folder. -* Each integration is placed in the relevant subfolder based on its category: - * `ai` - AI and machine learning integrations - * `caching` - Caching solutions (Redis, Garnet, Valkey, etc.) - * `cloud` - Cloud-specific integrations (Azure, AWS, etc.) - * `compute` - Compute platforms (Docker, Kubernetes, etc.) - * `databases` - Database systems - * `frameworks` - Language and framework integrations (Python, Rust, .NET MAUI, Orleans, etc.) - * `messaging` - Message brokers and queues - * `observability` - Logging, monitoring, and diagnostics tools - * `reverse-proxies` - Reverse proxy solutions - * `security` - Security and identity management -* Documentation is written using the Astro framework and uses `.mdx` files. +- Documentation will be created in the `src/frontend/src/content/docs/integrations` folder. +- Each integration is placed in the relevant subfolder based on its category: + - `ai` - AI and machine learning integrations + - `caching` - Caching solutions (Redis, Garnet, Valkey, etc.) + - `cloud` - Cloud-specific integrations (Azure, AWS, etc.) + - `compute` - Compute platforms (Docker, Kubernetes, etc.) + - `databases` - Database systems + - `frameworks` - Language and framework integrations (Python, Rust, .NET MAUI, Orleans, etc.) + - `messaging` - Message brokers and queues + - `observability` - Logging, monitoring, and diagnostics tools + - `reverse-proxies` - Reverse proxy solutions + - `security` - Security and identity management +- Documentation is written using the Astro framework and uses `.mdx` files. ## Requirements -* A Community Toolkit integration is to be provided to generate the documentation for. -* Should no integration be provided, do not continue, instead request the user to provide one. -* The Community Toolkit is found at https://github.com/CommunityToolkit/Aspire -* README files for integrations are in the `src` folder of the Community Toolkit repo, under the relevant integration subfolder (using the name of the integration, such as `CommunityToolkit.Aspire.Hosting.Ollama`, `CommunityToolkit.Aspire.Hosting.Rust`, `CommunityToolkit.Aspire.SurrealDB`, etc.). -* The README file of the integration should be used as the primary source of information for generating the documentation. +- A Community Toolkit integration is to be provided to generate the documentation for. +- Should no integration be provided, do not continue, instead request the user to provide one. +- The Community Toolkit is found at https://github.com/CommunityToolkit/Aspire +- README files for integrations are in the `src` folder of the Community Toolkit repo, under the relevant integration subfolder (using the name of the integration, such as `CommunityToolkit.Aspire.Hosting.Ollama`, `CommunityToolkit.Aspire.Hosting.Rust`, `CommunityToolkit.Aspire.SurrealDB`, etc.). +- The README file of the integration should be used as the primary source of information for generating the documentation. ## Creating a plan 1. Review the README file of the provided Community Toolkit integration. 2. Identify the correct subfolder in the `src/frontend/src/content/docs/integrations` folder based on the integration's category. 3. Review existing integration documentation from this repo such as: - * `src/frontend/src/content/docs/integrations/ai/ollama.mdx` - * `src/frontend/src/content/docs/integrations/databases/kurrentdb.mdx` - * `src/frontend/src/content/docs/integrations/frameworks/python.mdx` - * `src/frontend/src/content/docs/integrations/frameworks/rust.mdx` + - `src/frontend/src/content/docs/integrations/ai/ollama.mdx` + - `src/frontend/src/content/docs/integrations/databases/kurrentdb.mdx` + - `src/frontend/src/content/docs/integrations/frameworks/python.mdx` + - `src/frontend/src/content/docs/integrations/frameworks/rust.mdx` 4. Create a plan for generating the documentation that includes: - * The target subfolder for the documentation. - * The filename for the documentation file (should be the name of the integration in lowercase, with spaces replaced by hyphens, and a `.mdx` extension). - * A breakdown of sections to include in the documentation, based on the README content and existing documentation style. + - The target subfolder for the documentation. + - The filename for the documentation file (should be the name of the integration in lowercase, with spaces replaced by hyphens, and a `.mdx` extension). + - A breakdown of sections to include in the documentation, based on the README content and existing documentation style. 5. Implement the plan by creating the necessary directories and files, and writing the documentation content in Astro format. ## Update the sidebar navigation @@ -53,12 +66,13 @@ After creating the documentation file, update `src/frontend/config/sidebar/sideb 1. Locate the relevant integration category section in the sidebar (e.g., "Frameworks & runtimes", "Data & databases", "Caching & state", etc.) 2. Add a new entry to the `items` array for that category: - * For simple entries: `{ label: "Integration Name", slug: "integrations/category/integration-name" }` - * For entries with subsections: Use a `collapsed` structure if the integration has multiple related docs + - For simple entries: `{ label: "Integration Name", slug: "integrations/category/integration-name" }` + - For entries with subsections: Use a `collapsed` structure if the integration has multiple related docs 3. Place the entry in alphabetical order within the category 4. Ensure the `slug` matches the documentation file path Example entry: + ```typescript { label: "My Integration", slug: "integrations/databases/my-integration" } ``` @@ -69,95 +83,104 @@ After completing all documentation writing and sidebar updates: 1. Execute the "Update Integration Documentation Links" prompt located at `.github/prompts/update-integrations.prompt.md` 2. This prompt will: - * Synchronize package names from the NuGet catalog with their corresponding documentation URLs - * Update `src/frontend/src/data/integration-docs.json` with mappings for the newly created documentation - * Ensure the new integration is discoverable through the integration gallery and search + - Synchronize package names from the NuGet catalog with their corresponding documentation URLs + - Update `src/frontend/src/data/integration-docs.json` with mappings for the newly created documentation + - Ensure the new integration is discoverable through the integration gallery and search This step ensures that the documentation you've created is properly indexed and linked in the Aspire documentation site. ## Documentation style and requirements ### Frontmatter -* **Title**: Should be concise and include "integration" (e.g., "Python integration", "Ollama integration") -* **Description**: A brief summary of what the integration does and its purpose. Required for all docs except framework integrations. - * For hosting integrations: Describe what the integration orchestrates/configures - * For client integrations: Describe what the client connects to and its purpose - * For combined integrations: Describe both aspects -* **Next**: Set to `false` for framework integrations that don't have natural next steps + +- **Title**: Should be concise and include "integration" (e.g., "Python integration", "Ollama integration") +- **Description**: A brief summary of what the integration does and its purpose. Required for all docs except framework integrations. + - For hosting integrations: Describe what the integration orchestrates/configures + - For client integrations: Describe what the client connects to and its purpose + - For combined integrations: Describe both aspects +- **Next**: Set to `false` for framework integrations that don't have natural next steps ### Required components and imports -* Import `Badge` from '@astrojs/starlight/components' and add `` at the top -* Import and use the `Aside` component for notes, tips, cautions, and warnings -* Import and use `AppHostLangPivot` for AppHost examples when both C# and TypeScript AppHost APIs are available -* Import and use `InstallPackage` for hosting packages -* Import and use `InstallDotNetPackage` for client packages -* Import `Image` from 'astro:assets' for icons + +- Import `Badge` from '@astrojs/starlight/components' and add `` at the top +- Import and use the `Aside` component for notes, tips, cautions, and warnings +- Import and use synced `Tabs` and `TabItem` from `@astrojs/starlight/components` for AppHost examples when both C# and TypeScript AppHost APIs are available. Use `syncKey='aspire-lang'` and tab IDs `csharp` and `typescript`. +- Import and use `InstallPackage` for hosting packages +- Import and use `InstallDotNetPackage` for client packages +- Import `Image` from 'astro:assets' for icons ### Icons and images -* Include an icon/logo at the top using the `Image` component (or `ThemeImage` if light/dark variants exist) -* Icon should be 100x100 pixels, float left, and have `data-zoom-off` attribute -* Image should include alt text describing the logo -* Icon files should be placed in `src/frontend/src/assets/icons/` -* If no official icon is available, the integration may proceed without one (do not use placeholder images) + +- Include an icon/logo at the top using the `Image` component (or `ThemeImage` if light/dark variants exist) +- Icon should be 100x100 pixels, float left, and have `data-zoom-off` attribute +- Image should include alt text describing the logo +- Icon files should be placed in `src/frontend/src/assets/icons/` +- If no official icon is available, the integration may proceed without one (do not use placeholder images) ### Structure and sections #### For hosting-only integrations (e.g., Rust, Python): + 1. **Introduction paragraph**: Brief description of what the integration is and what it enables 2. **Prerequisites** (if any): Use an `Aside` with type="note" for requirements like installed tools 3. **Hosting integration section**: - * Package installation with `InstallPackage` - * "Add [Technology] resource" subsection with basic example - * Configuration subsections (endpoints, arguments, volumes, bind mounts, etc.) - * Working directory explanation if relevant + - Package installation with `InstallPackage` + - "Add [Technology] resource" subsection with basic example + - Configuration subsections (endpoints, arguments, volumes, bind mounts, etc.) + - Working directory explanation if relevant 4. **See also section**: Links to official docs, Community Toolkit repo, and related Aspire resources #### For hosting + client integrations (e.g., Ollama, KurrentDB): + 1. **Introduction paragraph**: Brief description with link to the technology's website 2. **Hosting integration section**: - * Package installation with `InstallPackage` - * "Add [Technology] resource" subsection - * Configuration subsections (volumes, bind mounts, parameters, etc.) - * "Hosting integration health checks" subsection (if applicable) + - Package installation with `InstallPackage` + - "Add [Technology] resource" subsection + - Configuration subsections (volumes, bind mounts, parameters, etc.) + - "Hosting integration health checks" subsection (if applicable) 3. **Client integration section**: - * Package installation with `InstallDotNetPackage` - * "Add [Technology] client" subsection - * "Add keyed [Technology] client" subsection (if supported) - * Include example of keyed services with reference to Microsoft docs - * **Configuration subsection** covering: - * Connection strings - * Configuration providers with `appsettings.json` example - * Inline delegates - * "Client integration health checks" subsection (if applicable) - * "Observability and telemetry" subsection (if applicable) with logging and tracing details + - Package installation with `InstallDotNetPackage` + - "Add [Technology] client" subsection + - "Add keyed [Technology] client" subsection (if supported) + - Include example of keyed services with reference to Microsoft docs + - **Configuration subsection** covering: + - Connection strings + - Configuration providers with `appsettings.json` example + - Inline delegates + - "Client integration health checks" subsection (if applicable) + - "Observability and telemetry" subsection (if applicable) with logging and tracing details 4. **See also section** ### Code blocks -* Use proper syntax highlighting: `csharp`, `json`, `sql`, etc. -* Include descriptive titles: `title="C# — AppHost.cs"`, `title="JSON — appsettings.json"` -* For C# code in AppHost, always end with `// After adding all resources, run the app...` comment -* Show complete, runnable examples -* Use proper formatting and indentation + +- Use proper syntax highlighting: `csharp`, `json`, `sql`, etc. +- Include descriptive titles: `title="C# — AppHost.cs"`, `title="JSON — appsettings.json"` +- For C# code in AppHost, always end with `// After adding all resources, run the app...` comment +- Show complete, runnable examples +- Use proper formatting and indentation ### AppHost language parity -* Follow the `doc-writer` skill's AppHost language parity guidance for all AppHost and hosting-integration examples. -* Always show both C# AppHost (`AppHost.cs`) and TypeScript AppHost (`apphost.ts`) variants inside `AppHostLangPivot` unless the feature is genuinely language-specific or TypeScript AppHost support does not exist yet. -* Before writing a TypeScript AppHost example, verify the API exists in the TypeScript AppHost SDK. Do not invent TypeScript samples. -* If TypeScript AppHost support is not available, show only the C# example without `AppHostLangPivot` and add a note that TypeScript AppHost support for the integration is not yet available. -* Use language-neutral prose around AppHost examples, such as "Add a resource to your AppHost" instead of C#-specific method instructions. + +- Follow the `doc-writer` skill's AppHost language parity guidance for all AppHost and hosting-integration examples. +- Always show both C# AppHost (`AppHost.cs`) and TypeScript AppHost (`apphost.ts`) variants inside synced `Tabs` (with `syncKey='aspire-lang'`) unless the feature is genuinely language-specific or TypeScript AppHost support does not exist yet. +- Before writing a TypeScript AppHost example, verify the API exists in the TypeScript AppHost SDK. Do not invent TypeScript samples. +- If TypeScript AppHost support is not available, show only the C# example without language tabs and add a note that TypeScript AppHost support for the integration is not yet available. +- Use language-neutral prose around AppHost examples, such as "Add a resource to your AppHost" instead of C#-specific method instructions. ### Writing style -* Use imperative mood for instructions ("call the method", not "you call the method") -* Be concise but complete -* Use `Aside` components for important notes, tips, cautions, and warnings -* Include explanations of what code does, especially for non-obvious patterns -* For required parameters, list them with bullet points and descriptions -* Reference NuGet packages with the 📦 emoji and link format: `[📦 PackageName](https://nuget.org/packages/PackageName)` + +- Use imperative mood for instructions ("call the method", not "you call the method") +- Be concise but complete +- Use `Aside` components for important notes, tips, cautions, and warnings +- Include explanations of what code does, especially for non-obvious patterns +- For required parameters, list them with bullet points and descriptions +- Reference NuGet packages with the 📦 emoji and link format: `[📦 PackageName](https://nuget.org/packages/PackageName)` ### Common patterns -* **Connection names**: Explain that the connection name in client must match the resource name in AppHost -* **Keyed services**: When showing keyed services, include link to Microsoft docs: `[.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services)` -* **Data volumes vs bind mounts**: Explain when data volumes are used to persist data outside container lifecycle -* **Health checks**: Mention what the health check verifies -* **Environment variables**: Explain common patterns for port configuration -* **WithReference**: Show how resources are referenced in other projects + +- **Connection names**: Explain that the connection name in client must match the resource name in AppHost +- **Keyed services**: When showing keyed services, include link to Microsoft docs: `[.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services)` +- **Data volumes vs bind mounts**: Explain when data volumes are used to persist data outside container lifecycle +- **Health checks**: Mention what the health check verifies +- **Environment variables**: Explain common patterns for port configuration +- **WithReference**: Show how resources are referenced in other projects diff --git a/.github/skills/doc-writer/SKILL.md b/.github/skills/doc-writer/SKILL.md index 17c876973..53b49a8b0 100644 --- a/.github/skills/doc-writer/SKILL.md +++ b/.github/skills/doc-writer/SKILL.md @@ -71,6 +71,7 @@ description: A brief summary of the page content (required for SEO) ``` Optional frontmatter fields: + - `next: false` - Disable "Next page" link for terminal pages - Custom metadata as needed by Starlight theme @@ -79,23 +80,30 @@ Optional frontmatter fields: Import Starlight components at the top of your MDX file: ```tsx -import { CardGrid, LinkCard, Steps, Tabs, TabItem, Icon, FileTree } from '@astrojs/starlight/components'; +import { + CardGrid, + LinkCard, + Steps, + Tabs, + TabItem, + Icon, + FileTree, +} from "@astrojs/starlight/components"; ``` Additional commonly used imports: ```tsx -import { Kbd } from 'starlight-kbd/components'; -import LearnMore from '@components/LearnMore.astro'; -import AppHostLangPivot from '@components/AppHostLangPivot.astro'; -import PivotSelector from '@components/PivotSelector.astro'; -import Pivot from '@components/Pivot.astro'; -import ThemeImage from '@components/ThemeImage.astro'; -import InstallPackage from '@components/InstallPackage.astro'; -import InstallDotNetPackage from '@components/InstallDotNetPackage.astro'; -import AsciinemaPlayer from '@components/AsciinemaPlayer.astro'; -import Badge from '@astrojs/starlight/components/Badge.astro'; -import Image from 'astro:assets'; +import { Kbd } from "starlight-kbd/components"; +import LearnMore from "@components/LearnMore.astro"; +import PivotSelector from "@components/PivotSelector.astro"; +import Pivot from "@components/Pivot.astro"; +import ThemeImage from "@components/ThemeImage.astro"; +import InstallPackage from "@components/InstallPackage.astro"; +import InstallDotNetPackage from "@components/InstallDotNetPackage.astro"; +import AsciinemaPlayer from "@components/AsciinemaPlayer.astro"; +import Badge from "@astrojs/starlight/components/Badge.astro"; +import Image from "astro:assets"; ``` ### Component Usage @@ -135,33 +143,34 @@ Critical warning - this could cause data loss or security issues. Use for sequential instructions: -```mdx +````mdx 1. First step with explanation - ```bash title="Run this command" - aspire new aspire-starter - ``` + ```bash title="Run this command" + aspire new aspire-starter + ``` 2. Second step 3. Third step -``` +```` #### Tabs/TabItem Use for language or platform-specific content: -```mdx +````mdx ```bash aspire run ``` +```` @@ -176,25 +185,23 @@ If a heading should appear in the **On this page** table of contents, keep that #### Pivot/PivotSelector -Use for programming language selection that persists across page navigations (for example, site-wide via query string and local storage). For Aspire AppHost C# and TypeScript content, use `AppHostLangPivot` instead; see [AppHost Language Parity (C# and TypeScript)](#apphost-language-parity-c-and-typescript). +Use `Pivot` and `PivotSelector` sparingly, only for **key landing-page-style articles** where the choice should persist across page navigations and where sharing the page through a URL should land the reader on a specific variant. Pivots support query string values to set the selected option (for example, `?aspire-lang=typescript`). Examples in use today include the [Build your first Aspire app](/get-started/first-app/) and [Deploy your first Aspire app](/get-started/deploy-first-app/) tutorials. + +For most pages — including AppHost C# and TypeScript code samples within a guide — prefer synced `Tabs` / `TabItem` blocks at the snippet level instead. See [AppHost Language Parity (C# and TypeScript)](#apphost-language-parity-c-and-typescript). ```mdx - -C# specific content here. - +C# specific content here. - -Python specific content here. - +Python specific content here. ``` If a heading needs to appear in the **On this page** table of contents, keep the heading outside the `Pivot` content and put only the variant-specific body content inside each `Pivot`. @@ -205,22 +212,36 @@ When a page shows the **On this page** table of contents (the default behavior u If your opening section is truly introductory, keep it as body copy without an `Overview` heading. If that section has a more specific purpose, use a descriptive heading such as `Key concepts`, `Prerequisites`, or another topic-specific label. +For Aspire AppHost code examples, use synced `Tabs` / `TabItem` blocks with `syncKey='aspire-lang'` at each code snippet. Do **not** add a page-level `PivotSelector` just to switch AppHost code samples between C# and TypeScript. Readers should be able to switch the language at the specific snippet they are reading. + +```mdx + + +C# example content here. + + + +TypeScript example content here. + + +``` + #### CardGrid and LinkCard Use for navigation and feature highlights: ```mdx - - + + /> ``` @@ -229,12 +250,13 @@ Use for navigation and feature highlights: Use the `Kbd` component from `starlight-kbd` to display keyboard shortcuts with OS-specific variants. This renders styled `` elements and automatically shows the correct shortcut for the reader's operating system. ```mdx -import { Kbd } from 'starlight-kbd/components'; +import { Kbd } from "starlight-kbd/components"; Open the Command Palette () ``` **Props**: + - `windows` — The shortcut for Windows (also used as the default/Linux fallback) - `mac` — The shortcut for macOS - `linux` — (optional) The shortcut for Linux, if different from Windows @@ -256,10 +278,10 @@ Press to start debugging. Use the `LearnMore` component to add a styled "learn more" link with an open-book icon. It provides a consistent visual pattern for directing readers to related documentation. ```mdx -import LearnMore from '@components/LearnMore.astro'; +import LearnMore from "@components/LearnMore.astro"; -For more information, see [Service Defaults](/fundamentals/service-defaults/). + For more information, see [Service Defaults](/fundamentals/service-defaults/). ``` @@ -274,7 +296,8 @@ aspire config set features:polyglotSupportEnabled true --global ``` -For more information, see [aspire config command reference](/reference/cli/commands/aspire-config-set/) + For more information, see [aspire config command + reference](/reference/cli/commands/aspire-config-set/) ::: ```` @@ -308,7 +331,7 @@ builder.Build().Run(); ````mdx ```typescript title="apphost.ts" -import { createBuilder } from './.modules/aspire.js'; +import { createBuilder } from "./.modules/aspire.js"; const builder = await createBuilder(); @@ -355,15 +378,15 @@ Aspire supports both **C# AppHosts** (`AppHost.cs`) and **TypeScript AppHosts** 3. **Neither language is the default**: Don't present C# first as the "real" example and TypeScript as an afterthought. Both tabs are equal peers. 4. **Verify TypeScript APIs exist**: Before writing a TypeScript example, confirm the API exists in the TypeScript AppHost SDK. Do not invent TypeScript samples — if you are unsure whether an API is available, flag it for review. -### AppHostLangPivot Pattern for AppHost Content +### AppHost tabs pattern for AppHost content -Use `AppHostLangPivot` for AppHost-specific content that changes between C# and TypeScript. The component is controlled by the site-wide AppHost selector in the sidebar, so it should be the default choice for AppHost walkthroughs, code samples, and prose that should switch together. +Use synced `Tabs` for AppHost-specific content that changes between C# and TypeScript. Each AppHost code snippet should provide its own language tabs and use `syncKey='aspire-lang'` so the user's language choice stays synchronized across snippets on the page. ````mdx -import AppHostLangPivot from '@components/AppHostLangPivot.astro'; +import { Tabs, TabItem } from "@astrojs/starlight/components"; - -
+ + ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); @@ -376,11 +399,11 @@ builder.AddProject("api") builder.Build().Run(); ``` -
-
+ + ```typescript title="apphost.ts" -import { createBuilder } from './.modules/aspire.js'; +import { createBuilder } from "./.modules/aspire.js"; const builder = await createBuilder(); @@ -392,27 +415,27 @@ await api.withReference(cache); await builder.build().run(); ``` -
-
+
+
```` -Use `AppHostLangPivot` for more than code blocks when needed. Entire paragraphs, lists, asides, or multi-step sections can live inside the `csharp` and `typescript` slots when the workflows differ. The pivot itself is the shared wrapper; the slot names are the language discriminator. +Use the same synced tabs pattern for more than code blocks when needed. Entire paragraphs, lists, asides, or multi-step sections can live inside the `csharp` and `typescript` tab items when the workflows differ. -Use `Tabs` for other concerns such as CLI vs IDE, deployment targets, or platform choices. Do not use `Tabs syncKey="apphost-lang"` for new AppHost content. +Use different `syncKey` values for other concerns such as CLI vs IDE, deployment targets, platform choices, or package managers. For AppHost language tabs, use exactly `syncKey='aspire-lang'`. -If a section heading should appear in the **On this page** table of contents, keep that heading outside `AppHostLangPivot`. Headings inside the `csharp` and `typescript` slots can be missed by the TOC generator, so the recommended pattern is a shared heading followed by an `AppHostLangPivot` containing only the language-specific body content. +If a section heading should appear in the **On this page** table of contents, keep that heading outside `Tabs`. Headings inside `TabItem` content may be skipped by the TOC generator, so the recommended pattern is a shared heading followed by tabs containing only the language-specific body content. ### Conventions -| Aspect | C# | TypeScript | -|---|---|---| -| File title | `title="AppHost.cs"` | `title="apphost.ts"` | -| Pivot wrapper | Shared `AppHostLangPivot` container | Shared `AppHostLangPivot` container | -| Language slot | `slot="csharp"` | `slot="typescript"` | -| Builder creation | `DistributedApplication.CreateBuilder(args)` | `import { createBuilder } from './.modules/aspire.js';` then newline for space followed by `await createBuilder();` | -| Method casing | PascalCase (`AddRedis`) | camelCase (`addRedis`) | -| Async pattern | Synchronous fluent calls | `await` each builder call | -| Build & run | `builder.Build().Run()` | `await builder.build().run()` | +| Aspect | C# | TypeScript | +| ---------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| File title | `title="AppHost.cs"` | `title="apphost.ts"` | +| Tab wrapper | Shared `` container | Shared `` container | +| Tab item | `` | `` | +| Builder creation | `DistributedApplication.CreateBuilder(args)` | `import { createBuilder } from './.modules/aspire.js';` then newline for space followed by `await createBuilder();` | +| Method casing | PascalCase (`AddRedis`) | camelCase (`addRedis`) | +| Async pattern | Synchronous fluent calls | `await` each builder call | +| Build & run | `builder.Build().Run()` | `await builder.build().run()` | ### Prose Guidelines @@ -423,19 +446,19 @@ When writing narrative text around AppHost examples: - ❌ "Call `builder.AddRedis()` in your _Program.cs_" (C#-specific) - ❌ "Add the following C# code to your AppHost" (when both languages should be shown) -When a concept differs between languages (e.g., configuration files, async patterns), explain both within the AppHostLangPivot slots or in language-neutral prose above the pivot. +When a concept differs between languages (e.g., configuration files, async patterns), explain both within the AppHost language tabs or in language-neutral prose above the tabs. ### When TypeScript Is Not Yet Supported -If a hosting integration does not yet have TypeScript AppHost support, show only the C# example without `AppHostLangPivot` and add a note: +If a hosting integration does not yet have TypeScript AppHost support, show only the C# example without language tabs and add a note: ```mdx ``` -Do **not** wrap a single language in `AppHostLangPivot` or a single-language `` component — that creates a misleading UI suggesting another option exists. +Do **not** wrap a single language in a single-language `` component — that creates a misleading UI suggesting another option exists. ## Integration Documentation @@ -443,18 +466,18 @@ Do **not** wrap a single language in `AppHostLangPivot` or a single-language ` +Technology logo Brief description of the technology and what the integration enables. @@ -483,8 +512,8 @@ Brief description of the technology and what the integration enables. ### Add [Technology] resource - -
+ + ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); @@ -495,11 +524,11 @@ var tech = builder.AddTechnology("tech"); builder.Build().Run(); ``` -
-
+ + ```typescript title="apphost.ts" -import { createBuilder } from './.modules/aspire.js'; +import { createBuilder } from "./.modules/aspire.js"; const builder = await createBuilder(); @@ -508,8 +537,8 @@ const tech = await builder.addTechnology("tech"); await builder.build().run(); ``` -
-
+
+
### Configuration options @@ -532,8 +561,8 @@ Include both hosting and client sections: ### Add [Technology] resource - -
+ + ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); @@ -546,11 +575,11 @@ builder.AddProject("api") builder.Build().Run(); ``` -
-
+ + ```typescript title="apphost.ts" -import { createBuilder } from './.modules/aspire.js'; +import { createBuilder } from "./.modules/aspire.js"; const builder = await createBuilder(); @@ -562,8 +591,8 @@ await api.withReference(tech); await builder.build().run(); ``` -
-
+ +
### Hosting integration health checks @@ -625,7 +654,7 @@ The connection name must match the resource name defined in the AppHost. For integrations from the [Aspire Community Toolkit](https://github.com/CommunityToolkit/Aspire), add the badge at the top: ```mdx -import Badge from '@astrojs/starlight/components/Badge.astro'; +import Badge from "@astrojs/starlight/components/Badge.astro"; ``` @@ -681,12 +710,12 @@ After adding integration documentation, run the update-integrations prompt to en Use consistent terminology throughout: -| Preferred | Avoid | -|-----------|-------| -| Aspire | .NET Aspire (except in formal/legal contexts) | -| AppHost | App Host, app host | -| resource | component (for AppHost resources) | -| integration | connector, plugin | +| Preferred | Avoid | +| ----------- | --------------------------------------------- | +| Aspire | .NET Aspire (except in formal/legal contexts) | +| AppHost | App Host, app host | +| resource | component (for AppHost resources) | +| integration | connector, plugin | ### Inclusive Language @@ -715,30 +744,30 @@ Place icons in `src/frontend/src/assets/icons/` ### Icon Usage ```mdx -import Image from 'astro:assets'; +import Image from "astro:assets"; import techIcon from "@assets/icons/technology.svg"; Technology logo ``` For light/dark theme variants: ```mdx -import ThemeImage from '@components/ThemeImage.astro'; +import ThemeImage from "@components/ThemeImage.astro"; ``` @@ -891,6 +920,7 @@ Install the [📦 Aspire.Hosting.Redis](https://nuget.org/packages/Aspire.Hostin ### See Also Sections End pages with a "See also" section linking to: + - Official technology documentation - Related Aspire documentation - NuGet package pages @@ -910,25 +940,23 @@ The aspire.dev site supports multiple languages. When creating new content: ```mdx ``` ### Version-Specific Information ```mdx - + ``` ### Feature Flags or Experimental Features ```mdx ``` @@ -965,15 +993,17 @@ The following rules are derived from common feedback patterns in documentation P ### Code Example Rules 1. **Use standard indentation**: For fluent APIs on newlines, use standard 4-space indentation, NOT alignment with the method call above - + ✅ Correct: + ```csharp builder.AddProject("api") .WithReference(redis) .WithExternalHttpEndpoints(); ``` - + ❌ Incorrect (aligned indentation): + ```csharp builder.AddProject("api") .WithReference(redis) diff --git a/.github/skills/update-integrations/SKILL.md b/.github/skills/update-integrations/SKILL.md index 443b05df4..b02d9f8ae 100644 --- a/.github/skills/update-integrations/SKILL.md +++ b/.github/skills/update-integrations/SKILL.md @@ -33,7 +33,7 @@ This skill keeps the documentation mappings in sync with the package catalog and - On `release/*` branches, official packages (`Aspire.*`) must resolve from the branch-specific public Azure Artifacts feed instead of nuget.org - Community Toolkit packages (`CommunityToolkit.Aspire.*`) always resolve from nuget.org - The branch name in this repo is expected to match the corresponding branch in `microsoft/aspire` (for example `release/13.2`) -- The release feed name follows `darc-pub-dotnet-aspire-{shortSha}` where `{shortSha}` is the first 8 characters of the head commit SHA for the matching Aspire release branch +- The release feed name follows `darc-pub-microsoft-aspire-{shortSha}` where `{shortSha}` is the first 8 characters of the head commit SHA for the matching Aspire release branch - The automation derives the NuGet service index from that feed name as `https://pkgs.dev.azure.com/dnceng/public/_packaging/{feed-name}/nuget/v3/index.json` #### Release feed resolution @@ -41,7 +41,7 @@ This skill keeps the documentation mappings in sync with the package catalog and The scripts use this precedence on `release/*` branches: 1. `ASPIRE_RELEASE_FEED_URL` — accepts the full NuGet service index URL, the Azure DevOps feed page URL, or the raw feed name -2. `ASPIRE_RELEASE_FEED_NAME` — explicit feed name such as `darc-pub-dotnet-aspire-aad16017` +2. `ASPIRE_RELEASE_FEED_NAME` — explicit feed name such as `darc-pub-microsoft-aspire-aad16017` 3. `ASPIRE_RELEASE_COMMIT` / `ASPIRE_RELEASE_COMMIT_SHA` — derives the feed name from the commit SHA prefix 4. Automatic lookup of the matching branch head via `git ls-remote` against `https://github.com/microsoft/aspire` diff --git a/src/apphost/Aspire.Dev.AppHost/Aspire.Dev.AppHost.csproj b/src/apphost/Aspire.Dev.AppHost/Aspire.Dev.AppHost.csproj index 40b6e17c6..590ee861d 100644 --- a/src/apphost/Aspire.Dev.AppHost/Aspire.Dev.AppHost.csproj +++ b/src/apphost/Aspire.Dev.AppHost/Aspire.Dev.AppHost.csproj @@ -1,4 +1,4 @@ - + Exe @@ -9,8 +9,8 @@ - - + + diff --git a/src/frontend/config/redirects.mjs b/src/frontend/config/redirects.mjs index ee61ec5bb..2a5a42ddb 100644 --- a/src/frontend/config/redirects.mjs +++ b/src/frontend/config/redirects.mjs @@ -101,4 +101,6 @@ export const redirects = { '/deployment/azure/aca-deployment-aspire-cli/': '/deployment/azure/container-apps/', '/deployment/azure/customize-container-apps/': '/deployment/azure/container-apps/', '/fundamentals/app-lifecycle/': '/deployment/app-lifecycle/', + '/dashboard/copilot/': '/dashboard/ai-coding-agents/', + '/dashboard/mcp-server/': '/get-started/aspire-mcp-server/', }; diff --git a/src/frontend/config/sidebar/dashboard.topics.ts b/src/frontend/config/sidebar/dashboard.topics.ts index 97870ca1f..a108599c3 100644 --- a/src/frontend/config/sidebar/dashboard.topics.ts +++ b/src/frontend/config/sidebar/dashboard.topics.ts @@ -107,49 +107,66 @@ export const dashboardTopics: StarlightSidebarTopicsUserConfig = { ], }, { - label: 'AI features', + label: 'Data features', translations: { - da: 'AI-funktioner', - de: 'KI-Funktionen', - en: 'AI features', - es: 'Funciones de IA', - fr: "Fonctionnalités d'IA", - hi: 'एआई सुविधाएँ', - id: 'Fitur AI', - it: "Funzionalità dell'IA", - ja: 'AI機能', - ko: 'AI 기능', - 'pt-BR': 'Recursos de IA', - ru: 'Функции ИИ', - tr: 'Yapay zeka özellikleri', - uk: 'Функції ШІ', - 'zh-CN': '人工智能功能', + da: 'Datafunktioner', + de: 'Datenfunktionen', + en: 'Data features', + es: 'Funciones de datos', + fr: 'Fonctionnalités de données', + hi: 'डेटा सुविधाएँ', + id: 'Fitur data', + it: 'Funzionalità dati', + ja: 'データ機能', + ko: '데이터 기능', + 'pt-BR': 'Recursos de dados', + ru: 'Функции данных', + tr: 'Veri özellikleri', + uk: 'Функції даних', + 'zh-CN': '数据功能', }, items: [ { - label: 'GitHub Copilot', - slug: 'dashboard/copilot', + label: 'AI coding agents', + translations: { + da: 'AI-kodningsagenter', + de: 'KI-Coding-Agenten', + en: 'AI coding agents', + es: 'Agentes de codificación de IA', + fr: "Agents de codage IA", + hi: 'एआई कोडिंग एजेंट', + id: 'Agen pengkodean AI', + it: 'Agenti di codifica AI', + ja: 'AIコーディングエージェント', + ko: 'AI 코딩 에이전트', + 'pt-BR': 'Agentes de codificação de IA', + ru: 'Агенты кодирования ИИ', + tr: 'Yapay zeka kodlama aracıları', + uk: 'Агенти кодування ШІ', + 'zh-CN': 'AI 编码代理', + }, + slug: 'dashboard/ai-coding-agents', }, { - label: 'Aspire MCP server', + label: 'APIs and data access', translations: { - da: 'Aspire MCP-server', - de: 'Aspire MCP-Server', - en: 'Aspire MCP server', - es: 'Servidor Aspire MCP', - fr: 'Serveur Aspire MCP', - hi: 'Aspire MCP सर्वर', - id: 'Server Aspire MCP', - it: 'Server Aspire MCP', - ja: 'Aspire MCPサーバー', - ko: 'Aspire MCP 서버', - 'pt-BR': 'Servidor Aspire MCP', - ru: 'Сервер Aspire MCP', - tr: 'Aspire MCP sunucusu', - uk: 'Сервер Aspire MCP', - 'zh-CN': 'Aspire MCP 服务器', + da: 'API\'er og dataadgang', + de: 'APIs und Datenzugriff', + en: 'APIs and data access', + es: 'APIs y acceso a datos', + fr: 'APIs et accès aux données', + hi: 'APIs और डेटा एक्सेस', + id: 'API dan akses data', + it: 'API e accesso ai dati', + ja: 'APIとデータアクセス', + ko: 'API 및 데이터 액세스', + 'pt-BR': 'APIs e acesso a dados', + ru: 'API и доступ к данным', + tr: 'API\'ler ve veri erişimi', + uk: 'API та доступ до даних', + 'zh-CN': 'API 和数据访问', }, - slug: 'dashboard/mcp-server', + slug: 'dashboard/apis', }, ], }, diff --git a/src/frontend/config/sidebar/deployment.topics.ts b/src/frontend/config/sidebar/deployment.topics.ts index 46f7c54ce..c2c5a9c0b 100644 --- a/src/frontend/config/sidebar/deployment.topics.ts +++ b/src/frontend/config/sidebar/deployment.topics.ts @@ -110,10 +110,57 @@ export const deploymentTopics: StarlightSidebarTopicsUserConfig = { }, { label: 'Kubernetes', - slug: 'deployment/kubernetes', + collapsed: false, + items: [ + { + label: 'Overview', + slug: 'deployment/kubernetes', + }, + { + label: 'Kubernetes clusters', + slug: 'deployment/kubernetes/kubernetes', + }, + { + label: 'Azure Kubernetes Service (AKS)', + slug: 'deployment/kubernetes/aks', + }, + { + label: 'Ingress & Gateway API', + slug: 'deployment/kubernetes-ingress', + }, + { + label: 'Gateway API on AKS', + slug: 'deployment/kubernetes-gateway-aks', + }, + { + label: 'Ingress on AKS', + slug: 'deployment/kubernetes-ingress-aks', + }, + ], + }, + { + label: 'Custom deployment pipelines', + translations: { + da: 'Brugerdefinerede implementeringspipelines', + de: 'Benutzerdefinierte Bereitstellungspipelines', + en: 'Custom deployment pipelines', + es: 'Canalizaciones de despliegue personalizadas', + fr: 'Pipelines de déploiement personnalisés', + hi: 'कस्टम तैनाती पाइपलाइन', + id: 'Pipeline penyebaran kustom', + it: 'Pipeline di distribuzione personalizzate', + ja: 'カスタム デプロイ パイプライン', + ko: '사용자 지정 배포 파이프라인', + 'pt-BR': 'Pipelines de implantação personalizados', + ru: 'Пользовательские конвейеры развертывания', + tr: 'Özel dağıtım işlem hatları', + uk: 'Користувацькі конвеєри розгортання', + 'zh-CN': '自定义部署管道', + }, + slug: 'deployment/custom-deployments', }, { - label: 'Azure', + label: 'Deploy to Azure', collapsed: false, items: [ { diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index 34778aaaf..53fa0a32c 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -90,6 +90,10 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { label: "What's new", collapsed: true, items: [ + { + label: 'Aspire 13.3', + slug: 'whats-new/aspire-13-3', + }, { label: 'Aspire 13.2', slug: 'whats-new/aspire-13-2', diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index e76c3e651..1fb6789de 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -473,6 +473,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { }, ], }, + { + label: 'Azure Kubernetes Service (AKS)', + slug: 'integrations/cloud/azure/aks', + }, { label: 'Azure Cosmos DB', collapsed: true, @@ -513,6 +517,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { }, ], }, + { + label: 'Azure Front Door', + slug: 'integrations/cloud/azure/azure-front-door', + }, { label: 'Azure Functions', collapsed: true, @@ -1553,6 +1561,27 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { 'zh-CN': '开发工具和扩展', }, items: [ + { + label: 'Browser logs', + translations: { + da: 'Browserlogfiler', + de: 'Browserprotokolle', + en: 'Browser logs', + es: 'Registros del navegador', + fr: 'Journaux du navigateur', + hi: 'ब्राउज़र लॉग', + id: 'Log browser', + it: 'Log del browser', + ja: 'ブラウザーログ', + ko: '브라우저 로그', + 'pt-BR': 'Logs do navegador', + ru: 'Журналы браузера', + tr: 'Tarayıcı günlükleri', + uk: 'Журнали браузера', + 'zh-CN': '浏览器日志', + }, + slug: 'integrations/devtools/browser-logs', + }, { label: 'Data API Builder', slug: 'integrations/devtools/dab' }, { label: 'Dev Tunnels', slug: 'integrations/devtools/dev-tunnels' }, { diff --git a/src/frontend/config/sidebar/reference.topics.ts b/src/frontend/config/sidebar/reference.topics.ts index 4a7b4af5b..38c83f06a 100644 --- a/src/frontend/config/sidebar/reference.topics.ts +++ b/src/frontend/config/sidebar/reference.topics.ts @@ -332,6 +332,20 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { }, ], }, + { + label: 'aspire dashboard', + collapsed: true, + items: [ + { + label: 'aspire dashboard', + slug: 'reference/cli/commands/aspire-dashboard', + }, + { + label: 'aspire dashboard run', + slug: 'reference/cli/commands/aspire-dashboard-run', + }, + ], + }, { label: 'aspire deploy', slug: 'reference/cli/commands/aspire-deploy', @@ -340,6 +354,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'aspire describe', slug: 'reference/cli/commands/aspire-describe', }, + { + label: 'aspire destroy', + slug: 'reference/cli/commands/aspire-destroy', + }, { label: 'aspire do', slug: 'reference/cli/commands/aspire-do' }, { label: 'aspire docs', @@ -361,6 +379,28 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'aspire docs search', slug: 'reference/cli/commands/aspire-docs-search', }, + { + label: 'aspire docs api', + collapsed: true, + items: [ + { + label: 'aspire docs api', + slug: 'reference/cli/commands/aspire-docs-api', + }, + { + label: 'aspire docs api get', + slug: 'reference/cli/commands/aspire-docs-api-get', + }, + { + label: 'aspire docs api list', + slug: 'reference/cli/commands/aspire-docs-api-list', + }, + { + label: 'aspire docs api search', + slug: 'reference/cli/commands/aspire-docs-api-search', + }, + ], + }, ], }, { @@ -536,6 +576,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'ASPIREEXPORT010', link: '/diagnostics/aspireexport010', }, + { + label: 'ASPIREEXPORT013', + link: '/diagnostics/aspireexport013', + }, { label: 'ASPIRECERTIFICATES001', link: '/diagnostics/aspirecertificates001', @@ -564,6 +608,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'ASPIREDOTNETTOOL', link: '/diagnostics/aspiredotnettool', }, + { + label: 'ASPIREDURABLETASK001', + link: '/diagnostics/aspiredurabletask001', + }, { label: 'ASPIREEXTENSION001', link: '/diagnostics/aspireextension001', @@ -576,6 +624,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'ASPIREINTERACTION001', link: '/diagnostics/aspireinteraction001', }, + { + label: 'ASPIREJAVASCRIPT001', + link: '/diagnostics/aspirejavascript001', + }, { label: 'ASPIREMCP001', link: '/diagnostics/aspiremcp001', @@ -661,6 +713,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { { label: 'ASPIREAZURE001', link: '/diagnostics/aspireazure001' }, { label: 'ASPIREAZURE002', link: '/diagnostics/aspireazure002' }, { label: 'ASPIREAZURE003', link: '/diagnostics/aspireazure003' }, + { + label: 'ASPIREBROWSERLOGS001', + link: '/diagnostics/aspirebrowserlogs001', + }, ], }, ], diff --git a/src/frontend/scripts/aspire-package-source.ts b/src/frontend/scripts/aspire-package-source.ts index 14d6ee453..68b47505d 100644 --- a/src/frontend/scripts/aspire-package-source.ts +++ b/src/frontend/scripts/aspire-package-source.ts @@ -58,7 +58,7 @@ function getReleaseFeedNameFromCommit(commit: string | undefined | null): string return null; } - return `darc-pub-dotnet-aspire-${normalizedCommit.slice(0, 8)}`; + return `darc-pub-microsoft-aspire-${normalizedCommit.slice(0, 8)}`; } function buildReleaseFeedServiceIndex(feedName: string): string { diff --git a/src/frontend/scripts/update-schemas.ts b/src/frontend/scripts/update-schemas.ts index 8ca056799..28f9fdf2b 100644 --- a/src/frontend/scripts/update-schemas.ts +++ b/src/frontend/scripts/update-schemas.ts @@ -3,8 +3,12 @@ * versioned copy under src/data/schemas/, then updates the version index. * * Usage: - * pnpm update:schemas # fetch latest non-prerelease - * pnpm update:schemas -- --version 13.2.3 # pin to a specific version tag + * pnpm update:schemas # fetch latest non-prerelease + * pnpm update:schemas -- --version 13.2.3 # pin to a specific version tag + * pnpm update:schemas -- --version 13.3.0 --ref # label as 13.3.0 but fetch from + * # the given commit SHA or branch ref + * # (used before the v tag is + * # published) */ import fs from 'fs'; @@ -73,15 +77,15 @@ async function fetchLatestReleaseVersion(): Promise { return stable.tag_name.replace(/^v/, ''); } -/** Fetch the raw schema JSON from microsoft/aspire at the given tag. */ -async function fetchSchemaAtTag(tag: string): Promise> { +/** Fetch the raw schema JSON from microsoft/aspire at the given git ref (tag, branch, or SHA). */ +async function fetchSchemaAtRef(ref: string): Promise> { const rawUrl = - `https://raw.githubusercontent.com/${ASPIRE_REPO}/v${tag}/${SCHEMA_SOURCE_PATH}`; + `https://raw.githubusercontent.com/${ASPIRE_REPO}/${ref}/${SCHEMA_SOURCE_PATH}`; const res = await fetch(rawUrl, { headers: { 'User-Agent': 'aspire-schema-updater' }, }); if (!res.ok) { - throw new Error(`Failed to fetch schema at tag v${tag}: ${res.status} ${res.statusText}`); + throw new Error(`Failed to fetch schema at ref ${ref}: ${res.status} ${res.statusText}`); } return (await res.json()) as Record; } @@ -128,13 +132,19 @@ async function main(): Promise { console.log(`✅ Latest stable release: ${version}`); } + const refArg = process.argv.indexOf('--ref'); + const ref = + refArg >= 0 && process.argv[refArg + 1] + ? process.argv[refArg + 1] + : `v${version}`; + const outFile = schemaFilePath(version); if (fs.existsSync(outFile)) { console.log(`ℹ️ Schema for v${version} already exists at ${path.relative(FRONTEND_ROOT, outFile)}`); } else { - console.log(`⬇️ Fetching schema from microsoft/aspire @ v${version}…`); - const schema = await fetchSchemaAtTag(version); + console.log(`⬇️ Fetching schema from microsoft/aspire @ ${ref}…`); + const schema = await fetchSchemaAtRef(ref); // Update $id to point to the versioned aspire.dev URL schema['$id'] = `${SITE_ORIGIN}${SCHEMA_BASE_PATH}/${version}.json`; diff --git a/src/frontend/src/assets/dashboard/explore/notification-center-bell.png b/src/frontend/src/assets/dashboard/explore/notification-center-bell.png new file mode 100644 index 000000000..589fb6d19 Binary files /dev/null and b/src/frontend/src/assets/dashboard/explore/notification-center-bell.png differ diff --git a/src/frontend/src/assets/dashboard/explore/notification-center-open.png b/src/frontend/src/assets/dashboard/explore/notification-center-open.png new file mode 100644 index 000000000..d1e384e29 Binary files /dev/null and b/src/frontend/src/assets/dashboard/explore/notification-center-open.png differ diff --git a/src/frontend/src/assets/dashboard/explore/notification-center-response.png b/src/frontend/src/assets/dashboard/explore/notification-center-response.png new file mode 100644 index 000000000..5c90eea97 Binary files /dev/null and b/src/frontend/src/assets/dashboard/explore/notification-center-response.png differ diff --git a/src/frontend/src/assets/icons/azure-front-door-icon.png b/src/frontend/src/assets/icons/azure-front-door-icon.png new file mode 100644 index 000000000..8b0f00c07 Binary files /dev/null and b/src/frontend/src/assets/icons/azure-front-door-icon.png differ diff --git a/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result-light.png b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result-light.png new file mode 100644 index 000000000..96b5f548b Binary files /dev/null and b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result-light.png differ diff --git a/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result.png b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result.png new file mode 100644 index 000000000..948fee383 Binary files /dev/null and b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-responses-result.png differ diff --git a/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message-light.png b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message-light.png new file mode 100644 index 000000000..bf432d241 Binary files /dev/null and b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message-light.png differ diff --git a/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message.png b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message.png new file mode 100644 index 000000000..73c7cd249 Binary files /dev/null and b/src/frontend/src/assets/integrations/cloud/azure/azure-ai-foundry/agent-send-message.png differ diff --git a/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-bell.png b/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-bell.png new file mode 100644 index 000000000..589fb6d19 Binary files /dev/null and b/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-bell.png differ diff --git a/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-open.png b/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-open.png new file mode 100644 index 000000000..d1e384e29 Binary files /dev/null and b/src/frontend/src/assets/whats-new/aspire-13.3/notification-center-open.png differ diff --git a/src/frontend/src/components/AppHostLangPivot.astro b/src/frontend/src/components/AppHostLangPivot.astro deleted file mode 100644 index a6785aea7..000000000 --- a/src/frontend/src/components/AppHostLangPivot.astro +++ /dev/null @@ -1,30 +0,0 @@ ---- -interface Props { - csharp?: string; - typescript?: string; -} - -const { csharp, typescript } = Astro.props as Props; -const hasCsharpSlot = Astro.slots.has('csharp'); -const hasTypescriptSlot = Astro.slots.has('typescript'); ---- - -
-
- {hasCsharpSlot ? : csharp} -
-
- {hasTypescriptSlot ? : typescript} -
-
- - \ No newline at end of file diff --git a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx index 15d44f8ac..cfd913f95 100644 --- a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx +++ b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx @@ -72,6 +72,37 @@ aspire certs trust You may need to reload your profile or start a new terminal session for the change to take effect. +### Developer certificate for DCP communication (Windows) + +By default, Aspire's internal Developer Control Plane (DCP) server uses an ephemeral localhost certificate it generates itself for TLS. On Windows, you can opt in to using your trusted Aspire developer certificate for DCP communication instead, which avoids trust issues caused by the ephemeral certificate not being in the system trust store. + +Set the `ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE` environment variable to `true` in your AppHost's `launchSettings.json` or as a system/user environment variable: + +```json title="Properties/launchSettings.json" +{ + "profiles": { + "https": { + "commandName": "Project", + "environmentVariables": { + "ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE": "true" + } + } + } +} +``` + +When this setting is enabled: + +- Aspire checks for a trusted developer certificate. +- If a trusted certificate is found, it is used to secure the DCP server. +- If no trusted certificate is found, Aspire falls back to the DCP-generated ephemeral certificate. +- This setting is only supported on Windows. On other platforms, a warning is logged and DCP falls back to its default ephemeral certificate. + + + ## HTTPS endpoint configuration HTTPS endpoint configuration determines which certificate a resource presents when serving HTTPS traffic. This is server-side certificate configuration for resources that host HTTPS/TLS endpoints. diff --git a/src/frontend/src/content/docs/app-host/configuration.mdx b/src/frontend/src/content/docs/app-host/configuration.mdx index 5b201341e..4d665aef4 100644 --- a/src/frontend/src/content/docs/app-host/configuration.mdx +++ b/src/frontend/src/content/docs/app-host/configuration.mdx @@ -77,9 +77,15 @@ In TypeScript AppHosts, profiles live in `aspire.config.json`: | Option | Default value | Description | | ---------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ASPIRE_ALLOW_UNSECURED_TRANSPORT` | `false` | Allows communication with the AppHost without https. `ASPNETCORE_URLS` (dashboard address) and `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` (AppHost resource service address) must be secured with HTTPS unless true. | -| `ASPIRE_CONTAINER_RUNTIME` | `docker` | Allows the user of alternative container runtimes for resources backed by containers. Possible values are `docker` (default) or `podman`. | -| `ASPIRE_VERSION_CHECK_DISABLED` | `false` | When set to `true`, Aspire doesn't check for newer versions on startup. | +| `ASPIRE_ALLOW_UNSECURED_TRANSPORT` | `false` | Allows communication with the AppHost without https. `ASPNETCORE_URLS` (dashboard address) and `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` (AppHost resource service address) must be secured with HTTPS unless true. | +| `ASPIRE_CONTAINER_RUNTIME` | `docker` | Allows the user of alternative container runtimes for resources backed by containers. Possible values are `docker` (default) or `podman`. | +| `ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE` | `false` | When set to `true`, Aspire uses its trusted developer certificate to secure the internal DCP server instead of an ephemeral certificate generated by DCP. This can help avoid certificate trust issues when the dev cert is already trusted. If no trusted developer certificate is found, Aspire falls back to the DCP-generated ephemeral certificate. Only supported on Windows. For more information, see [Certificate configuration](/app-host/certificate-configuration/). | +| `ASPIRE_ENVIRONMENT` | `null` | Configures the AppHost environment when no higher-priority environment source is set. If no environment is configured, the AppHost uses `Production`. | +| `ASPIRE_VERSION_CHECK_DISABLED` | `false` | When set to `true`, Aspire doesn't check for newer versions on startup. | + +## AppHost environment + +Use `ASPIRE_ENVIRONMENT` to set the environment name used by the AppHost while it evaluates the application model. Precedence is `--environment`, `DOTNET_ENVIRONMENT`, `ASPIRE_ENVIRONMENT`, then `Production`. This doesn't configure the dashboard's `ASPNETCORE_ENVIRONMENT` or automatically flow to child resources; set framework-specific variables on resources as needed. For details, see [Aspire environments](/deployment/environments/). ## Version update notifications @@ -122,7 +128,7 @@ By default, the dashboard is automatically started by the AppHost. The dashboard | `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`| `false` | Configures the dashboard to not use authentication and accept anonymous access. Sets frontend, OTLP, MCP, and API auth modes to `Unsecured`. | | `ASPIRE_DASHBOARD_FRONTEND_BROWSERTOKEN` | Automatically generated 128-bit entropy token. | Configures the frontend browser token. This is the value that must be entered to access the dashboard when the auth mode is BrowserToken. If no browser token is specified then a new token is generated each time the AppHost is launched. | | `ASPIRE_DASHBOARD_TELEMETRY_OPTOUT` | `false` | Configures the dashboard to never send [usage telemetry](/dashboard/microsoft-collected-dashboard-telemetry/). | -| `ASPIRE_DASHBOARD_AI_DISABLED` | `false` | [GitHub Copilot in the dashboard](/dashboard/copilot/) is available when the AppHost is launched by a supported IDE. When set to `true` Copilot is disabled in the dashboard and no Copilot UI is visible. | +| `ASPIRE_DASHBOARD_AI_DISABLED` | `true` | Reserved for future use. The in-dashboard GitHub Copilot UI was removed in Aspire 13.3. AI coding agents can still access telemetry data via the [Aspire CLI and MCP server](/dashboard/ai-coding-agents/). | | `ASPIRE_DASHBOARD_API_ENABLED` | `true` | Enables the dashboard [telemetry API](/dashboard/configuration/#api) (`/api/telemetry/*`) endpoints. The AppHost always sets this to `true`. | | `ASPIRE_DASHBOARD_FORWARDEDHEADERS_ENABLED` | `false` | Enables the Forwarded headers middleware that replaces the scheme and host values on the Request context with the values coming from the `X-Forwarded-Proto` and `X-Forwarded-Host` headers. | diff --git a/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx b/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx index b8a2c7818..999e63780 100644 --- a/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx +++ b/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx @@ -27,6 +27,7 @@ Learn more about [Docker Compose services](https://docs.docker.com/compose/compo | `build: ./path` | `builder.AddDockerfile("name", "./path")` | Build from specific path | | `build.context: ./app` | `builder.AddDockerfile("name", "./app")` | Build context | | `build.dockerfile: Custom.dockerfile` | `builder.Add*("name").WithDockerfile("Custom.dockerfile")` | Custom Dockerfile name | +| Generated Dockerfile | `builder.AddDockerfileBuilder("name", "./app", callback, stage: "runtime")` | Generate the Dockerfile from AppHost code | Learn more about [Docker Compose build reference](https://docs.docker.com/compose/compose-file/build/) and [WithDockerfile](/app-host/withdockerfile/). @@ -72,7 +73,8 @@ Learn more about [Docker Compose ports](https://docs.docker.com/compose/compose- |----------------|-------------| | `environment: KEY=value` | `.WithEnvironment("KEY", "value")`
Static environment variable | | `environment: KEY=${HOST_VAR}` | `.WithEnvironment(context => context.EnvironmentVariables["KEY"] = hostVar)`
Environment variable with callback context | -| `env_file: .env` | `.ConfigureEnvFile(env => { ... })`
Environment file generation (available in 13.1+) | +| `environment: KEY=${PARAM}` | `.AsEnvironmentPlaceholder(resource)` inside `.PublishAsDockerComposeService(...)`
Compose environment variable placeholder | +| `env_file: .env` | `.ConfigureEnvFile(env => { ... })`
Environment file customization (available in 13.1+) | Learn more about [Docker Compose environment](https://docs.docker.com/compose/compose-file/05-services/#environment) and [external parameters](/fundamentals/external-parameters/). @@ -107,7 +109,8 @@ Learn more about [Docker Compose depends_on](https://docs.docker.com/compose/com | Docker Compose | Aspire | Notes | |----------------|-------------|-------| | `networks: [backend]` | Automatic | Aspire handles networking automatically | -| Custom networks | Not needed | Service discovery handles inter-service communication | +| Service host name on a Compose network | `.GetHostAddressExpression(endpoint)` | Produces the generated Docker Compose service host name for an endpoint | +| Custom networks | `.ConfigureComposeFile(file => { ... })` | Customize the generated Compose file when automatic networking isn't enough | Learn more about [Docker Compose networks](https://docs.docker.com/compose/compose-file/05-services/#networks) and [service discovery](/fundamentals/service-discovery/). @@ -139,8 +142,8 @@ Learn more about [Docker Compose healthcheck](https://docs.docker.com/compose/co | Docker Compose | Aspire | Notes | |----------------|-------------|-------| -| `restart: unless-stopped` | Not supported | Restart policies aren't supported in Aspire | -| `restart: always` | Not supported | Restart policies aren't supported in Aspire | +| `restart: unless-stopped` | `.PublishAsDockerComposeService((resource, service) => service.Restart = "unless-stopped")` | Customize the generated Docker Compose service | +| `restart: always` | `.PublishAsDockerComposeService((resource, service) => service.Restart = "always")` | Customize the generated Docker Compose service | | `restart: no` | Default | No restart policy | diff --git a/src/frontend/src/content/docs/app-host/eventing.mdx b/src/frontend/src/content/docs/app-host/eventing.mdx index 20990fa24..46c88e294 100644 --- a/src/frontend/src/content/docs/app-host/eventing.mdx +++ b/src/frontend/src/content/docs/app-host/eventing.mdx @@ -22,7 +22,7 @@ The following events are available in the AppHost and occur in the following ord ### Subscribe to AppHost events -To subscribe to built-in AppHost events, use the eventing API on the builder: +To subscribe to built-in AppHost events, use the convenience extension methods directly on the builder. These methods return the same `IDistributedApplicationBuilder` instance so calls can be chained: @@ -32,8 +32,27 @@ using Microsoft.Extensions.Logging; var builder = DistributedApplication.CreateBuilder(args); -var cache = builder.AddRedis("cache"); +builder.OnBeforeStart(static (@event, cancellationToken) => +{ + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("BeforeStartEvent"); + return Task.CompletedTask; +}); + +builder.Build().Run(); +``` + +The following builder-level extension methods are available for AppHost events: + +| Method | Event | +|--------|-------| +| `OnBeforeStart` | `BeforeStartEvent` — raised before the AppHost starts | +| `OnBeforePublish` | `BeforePublishEvent` — raised before manifest publishing begins | +| `OnAfterPublish` | `AfterPublishEvent` — raised after manifest publishing completes | +If you need to subscribe via `IDistributedApplicationEventing` directly (for example, inside an `IDistributedApplicationEventingSubscriber`), you can use the lower-level `Eventing.Subscribe()` API: + +```csharp title="AppHost.cs" builder.Eventing.Subscribe( static (@event, cancellationToken) => { @@ -48,7 +67,6 @@ builder.Eventing.Subscribe( var logger = @event.Services.GetRequiredService>(); logger.LogInformation("AfterResourcesCreatedEvent"); return Task.CompletedTask; - }); builder.Build().Run(); ``` @@ -373,13 +391,13 @@ When publishing your application (generating deployment manifests), these events | `AfterPublishEvent` | After publishing completes | Perform cleanup or post-publish actions | ```csharp title="AppHost.cs" -builder.Eventing.Subscribe((@event, ct) => +builder.OnBeforePublish((@event, ct) => { // Validate resources before publishing return Task.CompletedTask; }); -builder.Eventing.Subscribe((@event, ct) => +builder.OnAfterPublish((@event, ct) => { // Post-publish actions return Task.CompletedTask; diff --git a/src/frontend/src/content/docs/app-host/executable-resources.mdx b/src/frontend/src/content/docs/app-host/executable-resources.mdx index 7571e062c..87671888c 100644 --- a/src/frontend/src/content/docs/app-host/executable-resources.mdx +++ b/src/frontend/src/content/docs/app-host/executable-resources.mdx @@ -43,7 +43,7 @@ builder.Build().Run(); ``` -```typescript title="apphost.ts" twoslash +```typescript title="apphost.ts" import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); @@ -147,16 +147,19 @@ var app = builder.AddExecutable("app", "node", ".", "app.js") ```typescript title="apphost.ts" twoslash -import { createBuilder } from './.modules/aspire.js'; +import { createBuilder, EndpointProperty } from './.modules/aspire.js'; const builder = await createBuilder(); const redis = await builder.addRedis("cache"); +const redisEndpoint = await redis.getEndpoint("tcp"); +const redisHost = await redisEndpoint.property(EndpointProperty.Host); +const redisPort = await redisEndpoint.property(EndpointProperty.Port); const app = await builder.addExecutable("app", "node", ".", ["app.js"]) .withReference(redis) - .withEnvironment("REDIS_HOST", redis.host) - .withEnvironment("REDIS_PORT", redis.port); + .withEnvironment("REDIS_HOST", redisHost) + .withEnvironment("REDIS_PORT", redisPort); ``` diff --git a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx index bb7d479dc..7d3739b06 100644 --- a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx @@ -154,8 +154,8 @@ await builder.build().run(); -