Skip to main content

cli-channel-debugging

Emulates any Aspire CLI build identity (channel, version, commit, package source) from a locally built CLI using ASPIRE_CLI_* environment variables and the install sidecar, so a reported bug can be reproduced and fixed locally without going through the install/PR loop. Use this when asked to reproduce channel/version/quality-specific CLI behavior, simulate a daily/staging/stable/PR build locally, or decide which override knobs to set for a given scenario.

来源信息

仓库
microsoft/aspire
最近来源活动
2026年9月25日 17:57
检测到的 SKILL.md 语言
英语
星标
6,370
分支
1,013

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
5 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
cli-channel-debugging
description
Emulates any Aspire CLI build identity (channel, version, commit, package source) from a locally built CLI using ASPIRE_CLI_* environment variables and the install sidecar, so a reported bug can be reproduced and fixed locally without going through the install/PR loop. Use this when asked to reproduce channel/version/quality-specific CLI behavior, simulate a daily/staging/stable/PR build locally, or decide which override knobs to set for a given scenario.
You are a specialized agent for reproducing version/channel/quality-specific Aspire CLI behavior from a **locally built CLI**. The CLI resolves its own identity (channel, version, commit, and — optionally — the directory it resolves `Aspire*` packages from) at startup. By setting a few environment variables (or an install sidecar), you can make `dotnet run --project src/Aspire.Cli -- <cmd>` behave as if it were any released, staging, daily, or PR build. This lets you reproduce a bug that only manifests on a specific build and fix it on the current branch — without waiting for an install or a PR build. Read `docs/specs/cli-identity-sidecar.md` for the full design. This skill is the operational matrix: which knobs to set for each scenario. ## ⛔ MANDATORY: State the scenario and exact knobs in chat before running Before you run **any** emulated CLI command, you MUST write a short line in chat declaring: 1. **Which scenario row** (1–7b below) you are emulating. 2. **The exact environment variables and values** you are setting (channel, version, commit, packages directory, etc.). 3. For `ASPIRE_CLI_PACKAGES`: that you **built/populated the directory yourself** and verified it is clean (exactly one version of each `Aspire*` package). Do **not** hand-wave "you populate the directory" — actually run the build/pack, show the command, and list what landed there. Example: > Using **Scenario 2** (PR build identity + locally built packages): > `ASPIRE_CLI_CHANNEL=pr-18087`, `ASPIRE_CLI_PACKAGES=<repo>/artifacts/packages/Release/Shipping`. > Packed locally with `./build.sh --pack -c Release`; verified Shipping has one version of each > `Aspire*` package. If you cannot determine the right knobs, ask — don't guess. ## The override knobs ### Identity environment variables (process-local; the source of truth) These are read by `IdentityResolver` and flow into `CliExecutionContext`. They change the CLI's **global identity**, so they affect hive discovery, package-channel selection, staging feed derivation, `--version`, telemetry identity tags, and the SDK-skew warning. They are **stripped before the CLI spawns child Aspire processes**, so they never leak into peer probes or `aspire doctor`'s child invocations — treat them as process-local test affordances. | Env var | Effect | |---|---| | `ASPIRE_CLI_CHANNEL` | Identity channel: `stable`, `staging`, `daily`, `local`, or `pr-<N>`. Drives hive selection and staging-feed provenance. | | `ASPIRE_CLI_VERSION` | Informational version (e.g. `13.5.0-preview.1.26310.9`). Drives version pins, the skew warning, and `--version` output. | | `ASPIRE_CLI_COMMIT` | Source commit SHA. Drives the staging darc feed name (`darc-pub-microsoft-aspire-<sha8>`). | | `ASPIRE_CLI_PACKAGES` | A flat directory of `.nupkg` files (e.g. `artifacts/packages/<Config>/Shipping`). The CLI synthesizes a package channel **named after `ASPIRE_CLI_CHANNEL`** that maps `Aspire*` to this directory (everything else → nuget.org), **replacing** any same-named built-in/discovered/PR channel. See the cleanliness caveat below. | | `ASPIRE_CLI_NUGET_SERVICE_INDEX` | Replaces the canonical `https://api.nuget.org/v3/index.json` URL the CLI writes into **newly generated** `NuGet.config` files. Never rewrites URLs read from existing configs. | When any of these is set, the CLI prints a yellow banner on **stderr**: `Aspire CLI is emulating identity '<channel>' version '<version>'...`. Seeing that banner confirms `IdentityOverridden` is true. ### Install sidecar (`.aspire-install.json`) The same values can come from the `channel`, `version`, `commit`, `nugetServiceIndexOverride`, and `packages` fields of an `.aspire-install.json` sidecar next to the CLI binary. Resolution order per field is **env var → sidecar field → assembly-baked stamp**. Use the sidecar when you want a persistent emulated identity for an installed binary; use env vars for one-off runs. Installer-authored `channel`, `version`, and `commit` fields describe the real installed identity and do not show the emulation banner, so use `aspire doctor --format Json` to confirm their source. The developer-only `nugetServiceIndexOverride` and `packages` sidecar fields still show the banner. ### Legacy PackagingService config keys (staging-feed routing only) These predate the global env vars and are **narrower**: they only influence staging-feed routing decisions inside `PackagingService`; they do **not** change the global identity, hive lookups, or `--version`. Set with `aspire config set -g <key> <value>`. | Config key | Effect | |---|---| | `overrideCliIdentityChannel` | Identity used for **staging-feed decisions only** (validated against the known channel set). | | `overrideCliInformationalVersion` | Informational version used to derive the staging SHA-specific feed URL. | | `overrideStagingFeed` | Forces staging to be available and points it at an explicit feed URL. | | `stagingPinToCliVersion` | When `true` (and using the shared feed), pins resolution to the CLI version. | **Prefer the `ASPIRE_CLI_*` env vars for whole-identity emulation.** Use the config keys only when you specifically want to exercise staging-feed routing from an otherwise-plain local build (the `eng/scripts/debug-staging.sh` / `debug-stable.sh` recipes do exactly this — see `docs/cli-staging-validation.md`). ## Running the local CLI under an emulated identity ```bash # From the repo root. Build once, then run with the knobs set: ASPIRE_CLI_CHANNEL=daily \ ASPIRE_CLI_VERSION=13.5.0-preview.1.26310.9 \ ASPIRE_CLI_COMMIT=95f0d2968... \ dotnet run --project src/Aspire.Cli -- <command> ``` You can also run the already-built binary directly to skip the rebuild: `artifacts/bin/Aspire.Cli/Debug/net11.0/aspire.dll` via `dotnet <dll> -- <command>`. Confirm the emulation took effect: `aspire --version` prints the emulated version, and the emulation banner appears on stderr. (Note: `aspire doctor` reports some fields from the physical binary by design — see the spec.) > **Polyglot channel resolution from a source build.** When you run a source (DEBUG) build from > inside the Aspire repo, `AspireRepositoryDetector` can match the repo's `Aspire.slnx` (it falls > back to the CLI binary's `Environment.ProcessPath`, not the apphost's location). For a polyglot > (TypeScript/Python) apphost that would force "project-reference mode" and short-circuit channel > resolution, so `aspire add` would silently resolve **stable nuget.org** packages instead of the > emulated channel's feed. To keep emulation faithful, `GuestAppHostProject.IsUsingProjectReferences` > now returns `false` whenever an `ASPIRE_CLI_*` identity override is active — so setting any > identity env var makes the source build resolve packages exactly like the installed CLI it is > emulating. (A real installed CLI is unaffected: Release builds only honor `ASPIRE_REPO_ROOT`.) ## Helper scripts (bundled with this skill) Two scripts live next to this `SKILL.md` (each with a `.sh` and a `.ps1` variant). Always prefer them over hand-typing versions — the daily/staging feeds are unsorted and interleave old `9.x` builds, so eyeballing "the latest" is error-prone. ### `get-aspire-channel-version.{sh,ps1}` — resolve the version to emulate Maps a channel to the exact feed the CLI's built-in package channels resolve `Aspire*` from (see `src/Aspire.Cli/Packaging/PackagingService.cs`), queries it anonymously, and prints **only** the latest version to stdout (diagnostics go to stderr), so it pipes cleanly into `ASPIRE_CLI_VERSION`: ```bash .agents/skills/cli-channel-debugging/get-aspire-channel-version.sh stable # -> 13.4.3 (nuget.org) .agents/skills/cli-channel-debugging/get-aspire-channel-version.sh daily # -> 13.5.0-preview.1.NNNNN.N (dnceng/dotnet9) .agents/skills/cli-channel-debugging/get-aspire-channel-version.sh staging --commit <sha> # darc-pub-microsoft-aspire-<sha8> export ASPIRE_CLI_VERSION="$(.agents/skills/cli-channel-debugging/get-aspire-channel-version.sh daily)" ``` Options: `--package <id>` (default `Aspire.Hosting.AppHost`, present on all three feeds and versioned identically to the product), `--stable-only` (daily/staging → stable-shaped only), `--prerelease` (stable → allow prereleases). Staging requires `--commit`; note darc feeds are per-RC-build and may have been garbage-collected for older commits (clean `404` = no such feed). ### `emulate-aspire-cli.{sh,ps1}` — one-line scenario setup (SOURCE it) Sets the `ASPIRE_CLI_*` env vars and defines an `aspire` function pointing at this repo's built CLI. For `stable`/`daily`/`staging` it auto-resolves the version via the resolver above. It **must be sourced** (bash/zsh) or **dot-sourced** (pwsh) so the env + function persist: ```bash # bash / zsh — builds the CLI, resolves the latest daily version, defines `aspire` source .agents/skills/cli-channel-debugging/emulate-aspire-cli.sh daily aspire --version # confirms the emulation banner + version ``` ```pwsh . .agents/skills/cli-channel-debugging/emulate-aspire-cli.ps1 staging -Commit <sha> aspire --version ``` Options: `--version <v>` / `-Version` (pin instead of auto-resolving; required for `local`/`pr-<N>`), `--commit` / `-Commit`, `--packages <dir>` / `-Packages` (sets `ASPIRE_CLI_PACKAGES`), `--config` / `-Config` (`Debug`|`Release`, default `Debug`), `--no-build` / `-NoBuild` (use an existing binary). ## Driving a scenario from a Terminal canvas (Copilot app) When running inside the Copilot app, give the user a live, reusable shell per scenario by opening a **Terminal canvas** rather than only running one-off `bash` tool commands. The flow: 1. **State the scenario + knobs in chat** (mandatory rule above) and, for feed-backed channels, resolve the real version first with `get-aspire-channel-version.sh` so the title and env are accurate. 2. Build the CLI once (`dotnet build src/Aspire.Cli/Aspire.Cli.csproj -p:SkipNativeBuild=true`), or let `emulate-aspire-cli.sh` build it. 3. `open_canvas` with `canvasId: "terminal"` and a descriptive `title` (e.g. `aspire (emulating daily 13.5.0-preview.1.NNNNN.N)`); pick a stable `instanceId` per scenario so re-opening focuses the same panel. Open a **separate** instance per identity so the user can keep, say, a `stable` and a `daily` terminal side by side. 4. Drive it with the `send_terminal_input` action (input must be an **object**, e.g. `{"input": "aspire --version"}`; a trailing Enter is added by default). The fastest setup is a single `source .agents/skills/cli-channel-debugging/emulate-aspire-cli.sh <channel>` line; otherwise send the `export ASPIRE_CLI_*` lines and the `aspire() { dotnet "<dll>" "$@"; }` function definition individually. 5. Verify with `aspire --version`. `read_terminal_output` may be unavailable in some app contexts ("Terminal not found or not running"); when it is, confirm the emulation independently by running the same env + built `aspire.dll` through a normal `bash` tool call and checking the banner + version match — the canvas keystrokes are still delivered for the user. Reuse `instanceId`s across turns so "the daily terminal" stays the same panel the user is looking at. ## The scenario matrix | # | Scenario | Identity | `Aspire*` package source | How | |---|---|---|---|---| | 1 | Local build + locally built packages (local hive) | `local` | `~/.aspire/hives/local/packages` **or** local `Shipping` dir | `./localhive.sh` (no env vars) — or `ASPIRE_CLI_PACKAGES=<Shipping>` | | 2 | PR build identity + locally built packages | `pr-<N>` | local `Shipping` dir | `ASPIRE_CLI_CHANNEL=pr-<N>` + `ASPIRE_CLI_PACKAGES=<Shipping>` | | 3 | PR build identity + CI-built packages, local CLI | `pr-<N>` | `~/.aspire/hives/pr-<N>/packages` | `get-aspire-cli-pr.sh --pr <N>`, then `ASPIRE_CLI_CHANNEL=pr-<N>` | | 4 | Latest daily, local CLI | `daily` | dnceng/dotnet9 daily feed | `ASPIRE_CLI_CHANNEL=daily` + `ASPIRE_CLI_VERSION` (+ `ASPIRE_CLI_COMMIT`) | | 5 | Staging, unstable version | `staging` | `darc-pub-microsoft-aspire-<sha8>` feed (quality Both) | `ASPIRE_CLI_CHANNEL=staging` + prerelease `ASPIRE_CLI_VERSION` + `ASPIRE_CLI_COMMIT` | | 6 | Staging, stable version | `staging` | `darc-pub-microsoft-aspire-<sha8>` feed (quality Both) | `ASPIRE_CLI_CHANNEL=staging` + stable-shaped `ASPIRE_CLI_VERSION` + `ASPIRE_CLI_COMMIT` | | 7 | Released build repro | `stable` | nuget.org | `ASPIRE_CLI_CHANNEL=stable` + released `ASPIRE_CLI_VERSION` | | 7b | Released repro + CLI+hosting fix spanning packages | `stable` | locally rebuilt `Shipping` dir | as 7 + `ASPIRE_CLI_PACKAGES=<clean-rebuilt-dir>` | ### Scenario 1 — Local build + locally built packages `./localhive.sh [-c Release|Debug] [-n <hive>]` packs NuGet packages into `artifacts/packages/<Config>/Shipping`, creates `~/.aspire/hives/<hive>/packages`, and installs the CLI to `~/.aspire/bin`. The installed CLI bakes a `local` identity and discovers the hive — no env vars needed. To skip the hive copy and point a dev-tree CLI straight at the packed output: ```bash ./build.sh --pack -c Release # -> artifacts/packages/Release/Shipping ASPIRE_CLI_PACKAGES="$PWD/artifacts/packages/Release/Shipping" \ dotnet run --project src/Aspire.Cli -- <cmd> ``` ### Scenario 2 — PR build identity + locally built packages (agent builds the packages) You (the agent) build the packages, then run the local CLI as the PR build: ```bash ./build.sh --pack -c Release # produces artifacts/packages/Release/Shipping # Verify the Shipping dir is clean (one version per Aspire* package) before running. ASPIRE_CLI_CHANNEL=pr-<N> \ ASPIRE_CLI_PACKAGES="$PWD/artifacts/packages/Release/Shipping" \ dotnet run --project src/Aspire.Cli -- <cmd> ``` `ASPIRE_CLI_PACKAGES` wins over a same-named hive or PR-install channel, so the CLI resolves `Aspire*` from your freshly built packages while presenting a `pr-<N>` identity. ### Scenario 3 — PR build identity + CI-built packages, local CLI Use this to test something locally against a PR's **CI-built** packages without rebuilding them: ```bash eng/scripts/get-aspire-cli-pr.sh --pr <N> # populates ~/.aspire/hives/pr-<N>/packages ASPIRE_CLI_CHANNEL=pr-<N> dotnet run --project src/Aspire.Cli -- <cmd> ``` No `ASPIRE_CLI_PACKAGES` — the local CLI discovers `~/.aspire/hives/pr-<N>` by name because its
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看