Skip to content
Closed
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
25 changes: 24 additions & 1 deletion .github/workflows/verify-telemetry-hook-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ jobs:
'src/Aspire.Cli/Agents/Hooks/track-telemetry.sh',
'src/Aspire.Cli/Agents/Hooks/track-telemetry.ps1'
)
$bundleDirectory = 'src/Aspire.Cli/Agents/AspireSkills/Embedded'
$requiredBundlePaths = @(
'src/Aspire.Cli/Agents/AspireSkills/AspireSkillsInstaller.cs',
'src/Aspire.Cli/Agents/AspireSkills/Embedded/aspire-skills.metadata.json',
'src/Aspire.Cli/Aspire.Cli.csproj'
)

# Disable rename detection so both the removed and added paths are checked.
$changedPaths = @(& git --no-pager diff --no-ext-diff --no-textconv --no-renames --name-only 'HEAD^1' HEAD -- @protectedPaths)
Expand All @@ -39,7 +45,24 @@ jobs:
}

if ($changedPaths.Count -gt 0 -and $env:PR_HEAD_REF -cne $allowedHeadRef) {
throw "Telemetry hook scripts can only change in PRs whose head branch is '$allowedHeadRef'. Make changes in microsoft/aspire-skills and use the synchronization workflow instead of editing these copies manually."
# A feature PR may consume a newly published bundle directly, but only when it carries
# every generated companion change. The separate bundle-verification workflow checks
# the archive attestation and the hook bytes against the pinned aspire-skills commit.
$bundleChangedPaths = @(& git --no-pager diff --no-ext-diff --no-textconv --no-renames --name-only 'HEAD^1' HEAD -- @requiredBundlePaths $bundleDirectory)
if ($LASTEXITCODE -ne 0) {
throw 'Could not inspect the generated Aspire skills bundle changes.'
}

$missingBundlePaths = @($requiredBundlePaths | Where-Object { $_ -notin $bundleChangedPaths })
$archiveChanged = $bundleChangedPaths | Where-Object {
$_ -match '^src/Aspire\.Cli/Agents/AspireSkills/Embedded/aspire-skills-.*\.(zip|tar\.gz|tgz)$'
}

if ($missingBundlePaths.Count -gt 0 -or -not $archiveChanged) {
throw "Telemetry hook scripts can only change on '$allowedHeadRef' or as part of a complete generated bundle update. Make changes in microsoft/aspire-skills and run the synchronization workflow instead of editing these copies manually."
}

Write-Host "Telemetry hook changes are part of a complete generated bundle update; canonical content is checked separately."
}

Write-Host 'Telemetry hook branch policy satisfied. Canonical content is checked separately.'
37 changes: 34 additions & 3 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,45 @@
<packageSource key="dotnet9-transport">
<package pattern="*WorkloadBuildTasks*" />
</packageSource>
<packageSource key="dotnet11">
<!-- Aspire.Cli pins prerelease NuGet.* builds ($(NuGetPackageVersionForCli)) that only exist here,
while the rest of the repo uses the stable NuGet.* versions that only exist on dotnet-public.
These exact patterns are required even though this source also maps "*": dotnet-public lists the
same packages exactly, and an exact pattern always beats a wildcard, so without them dotnet-public
would win NuGet.* outright and the CLI could not resolve its prereleases. Keeping both sources at
equal specificity makes NuGet search both. -->
<package pattern="NuGet.Common" />
<package pattern="NuGet.Commands" />
<package pattern="NuGet.DependencyResolver.Core" />
<package pattern="NuGet.LibraryModel" />
<package pattern="NuGet.ProjectModel" />
<package pattern="NuGet.Configuration" />
<package pattern="NuGet.Credentials" />
<package pattern="NuGet.Frameworks" />
<package pattern="NuGet.Packaging" />
<package pattern="NuGet.Protocol" />
<package pattern="NuGet.Resolver" />
<package pattern="NuGet.Versioning" />
<package pattern="*" />
</packageSource>
<packageSource key="dotnet-tools">
<package pattern="Microsoft.Diagnostics.NETCore.Client" />
<package pattern="Microsoft.Diagnostics.Runtime" />
</packageSource>
<packageSource key="dotnet-public">
<!-- See the note on dotnet11: these NuGet.* patterns keep both feeds at equal specificity. -->
<package pattern="NuGet.Common" />
<package pattern="NuGet.Commands" />
<package pattern="NuGet.Configuration" />
<package pattern="NuGet.Credentials" />
<package pattern="NuGet.DependencyResolver.Core" />
<package pattern="NuGet.Frameworks" />
<package pattern="NuGet.LibraryModel" />
<package pattern="NuGet.Packaging" />
<package pattern="NuGet.ProjectModel" />
<package pattern="NuGet.Protocol" />
<package pattern="NuGet.Resolver" />
<package pattern="NuGet.Versioning" />
<package pattern="*" />
<!-- These versions span dotnet-public and dotnet-tools. Map both sources at the same specificity so NuGet searches both. -->
<package pattern="Microsoft.Diagnostics.NETCore.Client" />
Expand All @@ -51,9 +85,6 @@
<packageSource key="dotnet10">
<package pattern="*" />
</packageSource>
<packageSource key="dotnet11">
<package pattern="*" />
</packageSource>
<packageSource key="dotnet-libraries">
<package pattern="Microsoft.DeveloperControlPlane*" />
</packageSource>
Expand Down
15 changes: 8 additions & 7 deletions docs/specs/bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ The Aspire Bundle distributes the CLI with its runtime components:

| Component | Deployment | Purpose |
|-----------|------------|---------|
| `aspire[.exe]` | Native AOT | CLI, including native development-certificate management |
| `managed/aspire-managed[.exe]` | Self-contained single-file executable | AppHost Server, NuGet operations, terminal hosting, and a Dashboard compatibility forwarder |
| `aspire[.exe]` | Native AOT | CLI, including native development-certificate management and in-process NuGet operations |
| `managed/aspire-managed[.exe]` | Self-contained single-file executable | AppHost Server, terminal hosting, and a Dashboard compatibility forwarder |
| `dashboard/Aspire.Dashboard[.exe]` | Native AOT | Dashboard web application |
| `dashboard/wwwroot/` and native dependencies | Publish assets | Dashboard scripts, styles, fonts, images, and SQLite native library |
| `dcp/` | Platform-specific native binaries | Developer Control Plane |

The bundle removes the need to acquire DCP and Dashboard separately when using the bundled components. Its pre-built AppHost Server and NuGet helper do not require a globally installed .NET SDK.
The bundle removes the need to acquire DCP and Dashboard separately when using the bundled components. Its pre-built AppHost Server and in-process NuGet client do not require a globally installed .NET SDK.

This does **not** mean every application can run without other prerequisites. .NET application development still requires the appropriate SDK, guest languages require their own toolchains, and container resources require a container runtime. Integration packages and application dependencies must be available locally or restored from their configured sources. Offline operation requires those dependencies to have been acquired already.

Expand All @@ -43,10 +43,11 @@ The managed helper contains its own runtime. The CLI and Dashboard are Native AO

```text
aspire (Native AOT CLI)
|
+-- in-process NuGet.Client: package search, restore, and probe manifests
|
+-- managed/aspire-managed
| +-- server: AppHost Server and integration loading
| +-- nuget: package search, restore, and probe manifests
| +-- terminalhost: terminal hosting
| +-- dashboard: compatibility forwarder to native Dashboard
|
Expand Down Expand Up @@ -231,7 +232,7 @@ The native-version gate and executable-selection behavior are defined in [Layout

## NuGet and AppHost Server

`aspire-managed nuget` provides package search, restore, and package probe-manifest generation without requiring a globally installed SDK. Its command definitions live in [Aspire.Managed/NuGet](../../src/Aspire.Managed/NuGet); use the subcommands' `--help` output for their current arguments.
The CLI calls NuGet.Client APIs in-process for package search, restore, asset selection, and package probe-manifest generation, without requiring a globally installed SDK or an `aspire-managed` subprocess. The implementation lives in [Aspire.Cli/NuGet](../../src/Aspire.Cli/NuGet).

The pre-built AppHost Server loads the integrations required by the project. Package restore artifacts and probe manifests are cached beneath `<workspace>/.aspire/integrations/`:

Expand Down Expand Up @@ -345,7 +346,7 @@ For the complete tool contract, see [CreateLayout](../../tools/CreateLayout/READ
- Extraction validates archive paths and links to prevent traversal outside the extraction root. Validate the staged layout before switching the active link.
- Version-rooted paths and leases protect running consumers from cleanup and mixed-version component selection during updates.
- Native Dashboard startup does not require a globally selected .NET runtime. The managed helper carries its runtime; SDK-based development remains a separate workflow.
- Package source configuration, authentication, and package trust remain the responsibility of the NuGet acquisition path. Bundling the NuGet helper does not remove those requirements.
- Package source configuration, authentication, and package trust remain the responsibility of the NuGet acquisition path. Running NuGet in-process does not remove those requirements.

## Validation

Expand All @@ -361,4 +362,4 @@ Tests cover different parts of the distribution contract:
| Native browser interactivity | `NativeAotDashboardTests`, including a working directory outside the publish directory and lease cleanup |
| CI selection and archives | Infrastructure workflow-selection and archive-download tests |

The dedicated native-archive workflow explicitly opts into the native browser test's outerloop category. Native executables must be exercised on a compatible runner; a successful cross-publish is not evidence that the target binary ran. See [build-cli-native-archives.yml](../../.github/workflows/build-cli-native-archives.yml) for the current matrix and execution exclusions.
The dedicated native-archive workflow explicitly opts into the native browser test's outerloop category. Native executables must be exercised on a compatible runner; a successful cross-publish is not evidence that the target binary ran. See [build-cli-native-archives.yml](../../.github/workflows/build-cli-native-archives.yml) for the current matrix and execution exclusions.
7 changes: 7 additions & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
<AzureMonitorOpenTelemetryExporterVersion>1.8.3</AzureMonitorOpenTelemetryExporterVersion>
<!-- Aspire.Cli uses a preview version of StreamJsonRpc which is needed for native AOT support. -->
<StreamJsonRpcPackageVersionForCli>2.23.32-alpha</StreamJsonRpcPackageVersionForCli>
<!-- Aspire.Cli runs NuGet restore in-process in a native AOT binary, which needs newer NuGet.*
builds than the stable versions the rest of the repo uses (see Directory.Packages.props).
These prereleases come from the dotnet11 feed, which does not carry the stable versions,
so NuGet.config maps NuGet.* to both feeds. -->
<NuGetPackageVersionForCli>7.12.0-rc.25</NuGetPackageVersionForCli>
<!-- MicroBuild.Core version for VS Code extension signing -->
<MicrosoftVisualStudioEngMicroBuildCoreVersion>1.0.0</MicrosoftVisualStudioEngMicroBuildCoreVersion>
</PropertyGroup>
Expand All @@ -69,6 +74,8 @@
<MicrosoftAspNetCoreTestHostNet11Version>11.0.0-rc.1.26425.128</MicrosoftAspNetCoreTestHostNet11Version>
<MicrosoftExtensionsCachingMemoryNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsCachingMemoryNet11Version>
<MicrosoftExtensionsConfigurationBinderNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsConfigurationBinderNet11Version>
<MicrosoftExtensionsConfigurationEnvironmentVariablesNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsConfigurationEnvironmentVariablesNet11Version>
<MicrosoftExtensionsFileSystemGlobbingNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsFileSystemGlobbingNet11Version>
<MicrosoftExtensionsHttpNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsHttpNet11Version>
<MicrosoftExtensionsLoggingNet11Version>11.0.0-rc.1.26425.128</MicrosoftExtensionsLoggingNet11Version>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion extension/schemas/aspire-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
]
}
],
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for spawned processes",
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for NuGet operations",
"default": true
},
"polyglotIntegrationFilterEnabled": {
Expand Down
2 changes: 1 addition & 1 deletion extension/schemas/aspire-global-settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
]
}
],
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for spawned processes",
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for NuGet operations",
"default": true
},
"polyglotIntegrationFilterEnabled": {
Expand Down
2 changes: 1 addition & 1 deletion extension/schemas/aspire-settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
]
}
],
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for spawned processes",
"description": "Enable or disable defaulting the DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable for NuGet operations",
"default": true
},
"polyglotIntegrationFilterEnabled": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal sealed class AspireSkillsInstaller(
AspireCliTelemetry telemetry,
ILogger<AspireSkillsInstaller> logger) : IAspireSkillsInstaller
{
internal const string Version = "0.0.2";
internal const string Version = "0.0.3";
internal const string GitHubRepository = "microsoft/aspire-skills";
internal const string ExpectedSourceRepository = $"https://github.com/{GitHubRepository}";
internal const string ExpectedWorkflowPath = ".github/workflows/publish.yml";
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"version": "0.0.2",
"version": "0.0.3",
"repository": "microsoft/aspire-skills",
"tag": "v0.0.2",
"assetName": "aspire-skills-v0.0.2.tgz",
"sha512": "8caa7a0639477a1d14da01483ff45d963ea157c6b2a6560df26d65eac991cb469e01cbdef1e3847d153573e61a4fffa15dd51c853a43afe4f1f1bd9fe0265102",
"tag": "v0.0.3",
"assetName": "aspire-skills-v0.0.3.tgz",
"sha512": "a5f8bd971b6aa0556994a6f6003d5a763056f6c64d1d9e6ae7a883ef9408c3d8a7689371c0499d980d4f82a9cd55e37cebd1e182e3cb71fc028380cec0ececad",
"hooks": {
"commitSha": "842c4fb8d9ff5f89bf3e5f6f16739a728b5ba77e",
"commitSha": "a83ca78b9d35b8238f9c4fdba72cb779defe2a90",
"files": {
"track-telemetry.sh": "73d44c910ac39c196b3cd4e0ff3993bbf05125a75a351e068e8d7a32d4c520f6ec8560397ccd722c21d2710949baeef40fcb25dcebed7314a7b03fd65af78e44",
"track-telemetry.ps1": "5311aba3e0087132d40c460276bd8cf889fc3a7c4dd9e110eea305ed95ef24dd5c837bcff276eb801c44270bba2ebe42e53b99244ec52ffac91f1ecb6b2a6618"
"track-telemetry.sh": "6fa64f350e2709a7abb52842232cc8d584e24d104b17a200a93ca4010d36a838dd1f6f73b83e92cd2ad0d8ad4abf9753323f840dc28625ccaf2f082097667181",
"track-telemetry.ps1": "303dc8d0eba181154222dacf6151d6bbe24614dd0e3144704fab1cb83c81f149e95cac47e87488357f0c04d232629a2f91f5551fe33e5c6c91f25a8f97aa0af3"
}
}
}
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Agents/Hooks/TelemetryHookConfigurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task<TelemetryHookConfigurationResult> ConfigureAsync(
// configured here even though they are detected/marked. The Copilot App and CLI share the
// same ~/.copilot hook location, so prefer the App display name when both are detected.
// This identifies the configuration target, not the hook event's client-name: the canonical
// v0.0.2 scripts report App events as copilot-cli. See https://github.com/microsoft/aspire-skills/issues/71.
// scripts currently report App events as copilot-cli. See https://github.com/microsoft/aspire-skills/issues/71.
var supported = new List<AgentClientKind>();
if (detectedClients.Contains(AgentClientKind.CopilotApp))
{
Expand Down
4 changes: 3 additions & 1 deletion src/Aspire.Cli/Agents/Hooks/track-telemetry.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ trap {
# Allowlist of Aspire-owned skill names (keep in sync with github.com/microsoft/aspire-skills).
# A shared .agents/skills directory can also contain third-party skills, so a path/name is only
# treated as Aspire when its skill segment is one of these.
$AspireSkills = @('aspire', 'aspire-init', 'aspireify', 'aspire-orchestration', 'aspire-deployment', 'aspire-monitoring')
$AspireSkills = @('aspire', 'aspire-init', 'aspireify', 'aspire-project-v2-migration', 'aspire-orchestration', 'aspire-deployment', 'aspire-monitoring')

$AspireMcpTools = @(
'doctor',
Expand Down Expand Up @@ -65,6 +65,8 @@ $AspireReferenceFiles = @(
'aspire-orchestration/references/detection.md',
'aspire-orchestration/references/resource-management.md',
'aspire-orchestration/references/safety-guardrails.md',
'aspire-project-v2-migration/references/compatibility-and-validation.md',
'aspire-project-v2-migration/references/migration-patterns.md',
'aspire/references/aspire-13-3-breaking-changes.md',
'aspire/references/aspire-13-5-breaking-changes.md',
'aspireify/references/apphost-wiring.md',
Expand Down
4 changes: 3 additions & 1 deletion src/Aspire.Cli/Agents/Hooks/track-telemetry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ trap emit_continue EXIT
# github.com/microsoft/aspire-skills). A shared .agents/skills directory can also contain
# third-party skills (dotnet-inspect, playwright, ...), so a path/name is only treated as
# Aspire when its skill segment is one of these.
ASPIRE_SKILLS="aspire aspire-init aspireify aspire-orchestration aspire-deployment aspire-monitoring"
ASPIRE_SKILLS="aspire aspire-init aspireify aspire-project-v2-migration aspire-orchestration aspire-deployment aspire-monitoring"

ASPIRE_MCP_TOOLS="doctor execute_resource_command get_doc list_apphosts list_console_logs list_docs list_integrations list_resources list_structured_logs list_trace_structured_logs list_traces refresh_tools search_docs select_apphost"

Expand All @@ -93,6 +93,8 @@ aspire-orchestration/references/app-commands.md
aspire-orchestration/references/detection.md
aspire-orchestration/references/resource-management.md
aspire-orchestration/references/safety-guardrails.md
aspire-project-v2-migration/references/compatibility-and-validation.md
aspire-project-v2-migration/references/migration-patterns.md
aspire/references/aspire-13-3-breaking-changes.md
aspire/references/aspire-13-5-breaking-changes.md
aspireify/references/apphost-wiring.md
Expand Down
Loading
Loading