diff --git a/.editorconfig b/.editorconfig index e5f6016..138c5a4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# Purview.BuildSdk 1.3.1 - managed file, do not edit +# Purview.BuildSdk 1.3.2 - managed file, do not edit # # This file is written by Purview.BuildSdk and is replaced whenever the SDK version changes. The version # on the first line is how the SDK recognises a file it owns: a .editorconfig without that marker is diff --git a/AGENTS.md b/AGENTS.md index abd2c24..dc7297c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,7 +77,7 @@ The authored set, and what each one answers: | [`purview-buildsdk-skill-tests`](./skills/purview-buildsdk-skill-tests/SKILL.md) | authoring a skill, and validating it with `Purview.Skills.Testing` | | [`purview-buildsdk-skill-installation`](./skills/purview-buildsdk-skill-installation/SKILL.md) | installing the skills a package ships, and the `PRSKL*` diagnostics | | [`purview-buildsdk-repository-review`](./skills/purview-buildsdk-repository-review/SKILL.md) | auditing a repository against the SDK's conventions | -| [`purview-buildsdk-justfile`](./skills/purview-buildsdk-justfile/SKILL.md) | adding or updating `just` recipes that run the skill targets | +| [`purview-buildsdk-skills-justfile`](./skills/purview-buildsdk-skills-justfile/SKILL.md) | adding or updating `just` recipes that run the skill targets | After editing one, run `just skills-validate` for the pack-time check and `just test` for the full rule set. @@ -208,7 +208,7 @@ cost was pure duplication. The remaining work is now paid only when somebody ask dotnet msbuild -t:RecommendPurviewSkills # report, never fail dotnet msbuild -t:VerifyPurviewSkills # report, and fail on anything unverifiable dotnet msbuild -t:InstallPurviewSkills # install every shipped skill at its package's commit -dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source, then 'skills update' +dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source: refresh, and add new skills dotnet msbuild -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist dotnet msbuild -t:FixPurviewSkills # remove the CLI's links from any other agent directory dotnet msbuild -t:ListPurviewSkills # what the restored packages ship @@ -248,7 +248,7 @@ own `.slnx` because the harness's lists projects as `` entries. **Install, update and fix run only when named — never automatically.** Two layers, both tested in `PurviewSkillTargetIsolationTests`: no SDK target hooks or depends on them (a structural scan of every `.props`/`.targets` under `Sdk/`, including `*DependsOn` properties), and `_GuardExplicitPurviewSkillsTarget` — first in each one's `DependsOnTargets` — fails with `PRSKL0009` when `BuildingProject`, `DesignTimeBuild` or `MSBuildIsRestoring` is true, which catches a consumer's own `AfterTargets="Build"` hook. Do not add a `BeforeTargets`/`AfterTargets` to any of them, and do not weaken the guard. -`UpdatePurviewSkills` (`ReadPurviewSkillsLockSources` inline task) re-adds each unique lockfile source once, naming only the skills the lockfile records for it. A source a restored package ships is re-added at **that package's commit**, never unpinned — re-adding it at latest would turn a satisfied entry into `PRSKL0011` drift. Every other source is re-added at latest. Then `skills update -y -p` runs per `PurviewSkillsUpdateMode` (`Auto`: only when the lockfile hash changed; `Always`; `Never`). `skills update` re-fetches each entry at its recorded ref — verified in the CLI source — so it cannot undo the pin. The re-adds use target batching (`_UpdatePurviewSkillsSource`) so each failure is attributed to its source (`PRSKL0008`, `ErrorAndContinue` so all are named); `-p:PurviewSkillsDryRun=true` prints and runs nothing. +`UpdatePurviewSkills` (`ReadPurviewSkillsLockSources` inline task) re-adds each unique lockfile source once, and **that is the whole update — `skills update` is never run**. `skills add` reinstalls every skill it selects (verified in the CLI source, skills 1.7.6: `installSkillForAgent` cleans each skill's folder and copies it again, skipping only when source and destination are the same folder), so one re-add both refreshes the installed skills and adds any the source has gained; `skills update` only re-fetches entries the lockfile already has, so it would add nothing. A source a restored package ships is re-added at **that package's commit**, never unpinned — re-adding it at latest would turn a satisfied entry into `PRSKL0011` drift — naming every skill that package version ships. Every other source is re-added at latest with `--skill "*"`, never the lockfile's recorded names, which would leave out anything new. `PurviewSkillsUpdateMode` and `PRSKL0006` went with the `skills update` step. The re-adds use target batching (`_UpdatePurviewSkillsSource`) so each failure is attributed to its source (`PRSKL0008`, `ErrorAndContinue` so all are named); `-p:PurviewSkillsDryRun=true` prints and runs nothing. `CheckPurviewSkills`/`FixPurviewSkills` (`EnforcePurviewSkillDirectories`) do nothing unless `PurviewSkillsAgents` names agents. Then the only agent skill directories allowed are those agents', per the `PurviewSkillsAgentDirectory` item group (copied from the CLI's agent table — extend it, don't hard-code), plus `.agents/skills`, the canonical store every agent directory links into. The authored `skills/` folder is protected even though openclaw installs there. Fix deletes links only (never their targets — `RemoveDirectory` on Windows, `unlink` on Unix) and folders left empty; a real file is kept and reported as `PRSKL0015`, because it cannot be told from hand-written content. Note the CLI writes copies, not links, for some agent selections, so those are kept too. diff --git a/CHANGELOG.md b/CHANGELOG.md index bbba994..323f4c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,30 @@ release summarise what the commits recorded rather than what was written at the ## [Unreleased] +## [1.3.2] - 2026-11-09 + +### Changed + +- **`UpdatePurviewSkills` is re-add only.** `skills add` reinstalls every skill it selects, so one + re-add both refreshes the installed skills and adds any a source has gained; the trailing + `skills update -y -p` added nothing and is no longer run. +- **`UpdatePurviewSkills` picks up new skills from every source.** A source no package ships used to be + re-added naming only the skills `skills-lock.json` recorded, so a skill added to that repository + since the last install was never installed. It is now re-added with `--skill "*"`. Package sources + are unchanged: pinned to the package's commit, naming every skill that version ships. +- **The `purview-buildsdk-justfile` skill is now `purview-buildsdk-skills-justfile`.** A repository + that installed the old name keeps it until it is removed: run `npx skills add purview-dev/build-sdk` + for the new one and `npx skills remove purview-buildsdk-justfile` for the old. +- The skills-justfile skill now picks `skills_project` itself: an existing `Justfile` solution variable + first, then a solution path an existing recipe uses, then the repository's only solution file. + +### Removed + +- `PurviewSkillsUpdateMode`, and `PRSKL0006` with it: there is no `skills update` step left to + schedule. A value still set is ignored. + +## [1.3.1] - 2026-11-09 + ### Added - **`UpdatePurviewSkills`** re-adds every unique source in `skills-lock.json`, naming only the skills @@ -394,7 +418,10 @@ dotnet msbuild -t:VerifyPurviewSkills - `.editorconfig` values missing test projects. - Source-generator resolution on pack. -[Unreleased]: https://github.com/purview-dev/build-sdk/compare/v1.2.0...HEAD +[Unreleased]: https://github.com/purview-dev/build-sdk/compare/v1.3.2...HEAD +[1.3.2]: https://github.com/purview-dev/build-sdk/compare/v1.3.1...v1.3.2 +[1.3.1]: https://github.com/purview-dev/build-sdk/compare/v1.3.0...v1.3.1 +[1.3.0]: https://github.com/purview-dev/build-sdk/compare/v1.2.0...v1.3.0 [1.2.0]: https://github.com/purview-dev/build-sdk/compare/v1.1.0...v1.2.0 [1.1.0]: https://github.com/purview-dev/build-sdk/compare/v1.0.7...v1.1.0 [1.0.7]: https://github.com/purview-dev/build-sdk/compare/v1.0.6...v1.0.7 diff --git a/Justfile.skills.just b/Justfile.skills.just index 7ac2bea..65f5455 100644 --- a/Justfile.skills.just +++ b/Justfile.skills.just @@ -48,13 +48,14 @@ skills-list *args: skills-recommend *args: dotnet msbuild "{{ skills_project }}" -t:RecommendPurviewSkills -v:n {{ args }} -# Update the agent skills by re-adding every unique source in skills-lock.json, then 'skills update' +# Update the agent skills by re-adding every unique source in skills-lock.json # -# Skills a referenced package ships are re-added at that package's commit. When PurviewSkillsAgents +# The re-add refreshes installed skills and adds any a source has gained; 'skills update' is never +# run. Skills a referenced package ships are re-added at that package's commit. When PurviewSkillsAgents # is set, the agent directories it does not select are cleaned up afterwards (FixPurviewSkills); # when it is not, the skills CLI auto-detects agents and the cleanup does nothing. # -# just skills-update -p:PurviewSkillsUpdateMode=Always -p:PurviewSkillsDryRun=true +# just skills-update -p:PurviewSkillsDryRun=true # just skills-update -p:PurviewSkillsRunner=npx -p:PurviewSkillsAgents=universal # # Update the agent skills by re-adding every unique source in skills-lock.json diff --git a/README.md b/README.md index 4b1de60..ff272a6 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ A reusable MSBuild SDK NuGet package that delivers standardised .NET project def "runner": "Microsoft.Testing.Platform" }, "msbuild-sdks": { - "Purview.BuildSdk": "1.3.1" + "Purview.BuildSdk": "1.3.2" } } ``` @@ -201,7 +201,7 @@ to a low-importance message) and only a copy that still fails after every retry The bootstrapped `.editorconfig` opens with a version marker: ```editorconfig -# Purview.BuildSdk 1.3.1 - managed file, do not edit +# Purview.BuildSdk 1.3.2 - managed file, do not edit ``` That line is how the SDK recognises a file **it** wrote. When the SDK version changes, a file carrying @@ -286,7 +286,7 @@ as a side effect of a restore or a build. bun x skills add purview-dev/build-sdk # install, the ordinary way dotnet msbuild -t:RecommendPurviewSkills # what is missing, drifted or unverifiable dotnet msbuild -t:InstallPurviewSkills # explicit; delegates to the CLI -dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source, then 'skills update' +dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source: refresh, and add new skills dotnet msbuild -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist dotnet msbuild -t:FixPurviewSkills # remove the CLI's links from any other agent directory ``` @@ -433,7 +433,6 @@ Non-packable projects (including web applications) default `WarnOnPackingNonPack | `PurviewSkillsLockFile` | `/skills-lock.json` | Overrides where the skills CLI's lockfile is read from. | | `PurviewSkillsSourceFolder` | `/skills` | Repository folder holding authored skills. | | `PurviewSkillsAgents` | *(empty — the CLI auto-detects)* | Comma-separated agents the skill targets install to, and that recommended commands name. When set, `CheckPurviewSkills`/`FixPurviewSkills` allow only those agents' skill directories. | -| `PurviewSkillsUpdateMode` | `Auto` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (only when `skills-lock.json` changed), `Always` or `Never`. | | `PurviewSkillsDryRun` | `false` | When `true`, `InstallPurviewSkills` and `UpdatePurviewSkills` print the CLI commands without running them. | | `PurviewSkillsRunner` | `bun` | Package runner used to launch the skills CLI (`bun`, `npx`, `bunx`, `pnpm`, `yarn`, `deno`, `skills`, or any other). | | `PurviewSkillsRunnerCandidates` | `bun;npx;bunx;pnpm;yarn;deno` | Runners probed on `PATH` after `PurviewSkillsRunner`. | @@ -537,7 +536,6 @@ The SDK now exports its properties via `CompilerVisibleProperty`, so analyzers a | `PurviewSkillsLockFile` | Where the skills CLI's `skills-lock.json` is read from (default `/skills-lock.json`). | | `PurviewSkillsSourceFolder` | Repository folder holding authored agent skills (default `/skills`). | | `PurviewSkillsAgents` | Comma-separated agents the skill targets install to (default empty: the CLI auto-detects). | -| `PurviewSkillsUpdateMode` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (default), `Always` or `Never`. | | `PurviewSkillsDryRun` | When `true`, `InstallPurviewSkills` and `UpdatePurviewSkills` print commands without running them. | | `PurviewSkillsRunner` | Package runner used to launch the skills CLI (default `bun`; also `npx`, `bunx`, `pnpm`, `yarn`, `deno`, `skills`). | | `PurviewSkillsRunnerCandidates` | Runners probed on `PATH` after `PurviewSkillsRunner` (default `bun;npx;bunx;pnpm;yarn;deno`). | diff --git a/docs/wiki/Agent-Skills.md b/docs/wiki/Agent-Skills.md index 3bf8c95..5d6cff9 100644 --- a/docs/wiki/Agent-Skills.md +++ b/docs/wiki/Agent-Skills.md @@ -170,7 +170,7 @@ because somebody named it. | `RecommendPurviewSkills` | Reports the state. Never fails a build. | | `VerifyPurviewSkills` | The same report, escalating `PRSKL0010`/`PRSKL0011` to an error. The CI gate. | | `InstallPurviewSkills` | Installs every skill the restored packages ship, pinned to each package's commit, via the skills CLI. | -| `UpdatePurviewSkills` | Re-adds every source in `skills-lock.json` — package skills at their package's commit — then runs `skills update`. See [Updating](#updating). | +| `UpdatePurviewSkills` | Re-adds every source in `skills-lock.json` — package skills at their package's commit — refreshing installed skills and adding new ones. See [Updating](#updating). | | `CheckPurviewSkills` | Fails when an agent skill directory exists for an agent `PurviewSkillsAgents` does not name. See [Choosing agents](#choosing-agents). | | `FixPurviewSkills` | Removes the CLI's links from those directories, keeping and reporting anything real. | | `ListPurviewSkills` | Lists what the restored packages ship. Installs nothing. | @@ -183,7 +183,6 @@ A correctly installed set produces no output at all from either reporting target | -- | -- | -- | | `PurviewSkillsLockFile` | `/skills-lock.json` | Overrides where the CLI's lockfile is read from. | | `PurviewSkillsAgents` | *(empty — the CLI auto-detects)* | Agents the skill targets install to and recommended commands name; when set, the only agent skill directories `CheckPurviewSkills` allows. | -| `PurviewSkillsUpdateMode` | `Auto` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (only when the lockfile changed), `Always` or `Never`. | | `PurviewSkillsDryRun` | `false` | Print the install and update commands without running them. | | `PurviewSkillsRunner` | `bun` | Package runner used to launch the CLI. | | `PurviewSkillsRunnerCandidates` | `bun;npx;bunx;pnpm;yarn;deno` | Probed in order after `PurviewSkillsRunner`. | @@ -219,9 +218,9 @@ bun x skills add "purview-dev/purview-example#0123456789abcdef0123456789abcdef01 --skill "purview-alpha" -y ``` -A bare re-add or `bun x skills update` is only right for skills no package version speaks for. -`UpdatePurviewSkills` does both, but re-adds a package's skills at that package's commit first — and -`skills update` re-fetches each entry at the ref the lockfile records, so it does not undo the pin. +A re-add at latest is only right for skills no package version speaks for. `UpdatePurviewSkills` +re-adds those at latest and a package's skills at that package's commit, and never runs +`skills update`. > Note the repeated `--skill` flag. The CLI does not split a comma-separated value: given one, it > matches nothing and reports "No matching skills found". @@ -255,7 +254,7 @@ Installation is **explicit**. None of these targets has `BeforeTargets`/`AfterTa ```bash dotnet msbuild -t:ListPurviewSkills # diagnostics only, installs nothing dotnet msbuild -t:InstallPurviewSkills # delegates to the skills CLI -dotnet msbuild -t:UpdatePurviewSkills # re-add every lockfile source, then 'skills update' +dotnet msbuild -t:UpdatePurviewSkills # re-add every lockfile source: refresh, and add new skills dotnet msbuild -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist dotnet msbuild -t:FixPurviewSkills # remove the CLI's links from any other agent directory ``` @@ -269,14 +268,14 @@ however many projects it holds, because every project hands the work to the same project and MSBuild's result cache runs it once. Package resolution reads every project in the solution, so a package only a test project references is still found; a single project sees only its own packages. For `just` recipes, see the -[`purview-buildsdk-justfile` skill](../../skills/purview-buildsdk-justfile/SKILL.md). +[`purview-buildsdk-skills-justfile` skill](../../skills/purview-buildsdk-skills-justfile/SKILL.md). `InstallPurviewSkills` shells out to the CLI rather than reimplementing it, because the CLI owns the agent-specific destinations and their discovery conventions — which differ per agent and change independently of this SDK — and owns `skills-lock.json`. `InstallPurviewSkills` installs every skill the restored packages ship, not only the missing ones. -Re-running it is idempotent: the CLI skips a skill already installed from the same source and ref. +Re-running it is safe: the CLI reinstalls each skill it is given, replacing the installed copy. ### Updating @@ -286,21 +285,23 @@ dotnet msbuild -t:RecommendPurviewSkills # optional: shows PRSKL0011 dotnet msbuild -t:UpdatePurviewSkills ``` -`UpdatePurviewSkills` reads `skills-lock.json` and re-adds each unique source once, naming only the -skills the lockfile records for it — an update never installs a skill nobody asked for: +`UpdatePurviewSkills` reads `skills-lock.json` and re-adds each unique source once. It updates with +`skills add` rather than `skills update`, so a skill a source has gained since the last install is +added as well as the installed ones refreshed: | Source | Re-added as | | -- | -- | -| shipped by a restored package | `#` — the commit that package version was built from, the same pinned add `PRSKL0011` recommends | -| anything else | `` — its latest | +| shipped by a restored package | `#`, naming every skill that package version ships — the commit it was built from, the same pinned add `PRSKL0011` recommends | +| anything else | ` --skill "*"` — its latest, with every skill it has | -Then it runs `skills update -y -p` according to `PurviewSkillsUpdateMode`: `Auto` (default) only when -the re-adds changed the lockfile, `Always`, or `Never`. Every source is attempted even when one fails; -each failure is named as `PRSKL0008`, and `skills update` is skipped. No lockfile is `PRSKL0007` — +That is the whole update. `skills add` reinstalls every skill it selects, so one re-add refreshes the +installed skills and adds the new ones; `skills update` would only re-fetch what the lockfile +already lists, and is never run. Every source is attempted even when one fails, and each failure is +named as `PRSKL0008`. No lockfile is `PRSKL0007` — install first. A CI job can then call `-t:VerifyPurviewSkills` to confirm nothing is left drifted. `InstallPurviewSkills` is also enough to move package skills to a new package version: it re-adds -each at its package's commit, and the CLI skips one already at that ref. +each at its package's commit. ### Choosing agents @@ -563,9 +564,9 @@ Verified against the `skills` CLI v1. | `PRSKL0003` | The repository root could not be resolved, so there is nowhere correct to install | | `PRSKL0004` | No package runner was found on `PATH` | | `PRSKL0005` | An authored skill is malformed | -| `PRSKL0006` | `PurviewSkillsUpdateMode` is not `Auto`, `Always` or `Never` | +| `PRSKL0006` | Retired, with `PurviewSkillsUpdateMode`: update no longer runs `skills update` | | `PRSKL0007` | `UpdatePurviewSkills` found no `skills-lock.json` to update from | -| `PRSKL0008` | Re-adding a lockfile source failed; `skills update` was skipped | +| `PRSKL0008` | Re-adding a lockfile source failed | | `PRSKL0009` | Install, update or fix was pulled into a build, a restore or a design-time build | | `PRSKL0010` | Skills a referenced package ships are not installed | | `PRSKL0011` | Installed skills are pinned to a different ref than the referenced package | diff --git a/docs/wiki/Getting-Started.md b/docs/wiki/Getting-Started.md index 1d534d2..017ed63 100644 --- a/docs/wiki/Getting-Started.md +++ b/docs/wiki/Getting-Started.md @@ -14,7 +14,7 @@ Add `Purview.BuildSdk` to the `msbuild-sdks` section so MSBuild can resolve the "runner": "Microsoft.Testing.Platform" }, "msbuild-sdks": { - "Purview.BuildSdk": "1.3.1" + "Purview.BuildSdk": "1.3.2" } } ``` diff --git a/package.json b/package.json index 8ec7966..71d3a7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "build-sdk", - "version": "1.3.1", + "version": "1.3.2", "homepage": "https://purview.dev/projects/build-sdk/", "bugs": { "url": "https://github.com/purview-dev/build-sdk/issues" diff --git a/skills/purview-buildsdk-adoption/SKILL.md b/skills/purview-buildsdk-adoption/SKILL.md index 5a4caf1..bb24fa3 100644 --- a/skills/purview-buildsdk-adoption/SKILL.md +++ b/skills/purview-buildsdk-adoption/SKILL.md @@ -106,7 +106,7 @@ cleaning them up are separate targets a person runs by name — `InstallPurviewS repository refuse to run inside a build (`PRSKL0009`). Do not hook them into one. The skills CLI does the installing, through `bun x` by default; with `PurviewSkillsAgents` unset it auto-detects agents. -If the repository uses `just`, add recipes for them — see `purview-buildsdk-justfile`. For what each +If the repository uses `just`, add recipes for them — see `purview-buildsdk-skills-justfile`. For what each target does and the `PRSKL*` diagnostics, see `purview-buildsdk-skill-installation`. ## Constraints diff --git a/skills/purview-buildsdk-configuration/SKILL.md b/skills/purview-buildsdk-configuration/SKILL.md index bcd1e2e..e081eac 100644 --- a/skills/purview-buildsdk-configuration/SKILL.md +++ b/skills/purview-buildsdk-configuration/SKILL.md @@ -112,11 +112,10 @@ on the command line, and a repository-wide choice belongs in `Directory.Build.pr | -- | -- | -- | | `PurviewSkillsRunner` | `bun` (`bun x skills`) | Which package runner launches the skills CLI | | `PurviewSkillsAgents` | empty — the CLI auto-detects | Agents to install to; when set, the only agent directories `CheckPurviewSkills` allows | -| `PurviewSkillsUpdateMode` | `Auto` | When `UpdatePurviewSkills` runs `skills update`: `Auto`, `Always`, `Never` | | `PurviewSkillsDryRun` | `false` | Install and update print commands instead of running them | On a command line, `dotnet msbuild -p:` splits values on `,` and `;` — write -`-p:PurviewSkillsAgents=claude-code%2Ccodex`. For `just` recipes, see `purview-buildsdk-justfile`. +`-p:PurviewSkillsAgents=claude-code%2Ccodex`. For `just` recipes, see `purview-buildsdk-skills-justfile`. ## Guidance when changing SDK configuration diff --git a/skills/purview-buildsdk-configuration/references/properties.md b/skills/purview-buildsdk-configuration/references/properties.md index d45ca48..21ddc7f 100644 --- a/skills/purview-buildsdk-configuration/references/properties.md +++ b/skills/purview-buildsdk-configuration/references/properties.md @@ -136,7 +136,7 @@ nothing else was left for the mirror to deliver. Covered in full by `purview-buildsdk-skill-installation`: `PurviewSkillsRunner`, `PurviewSkillsRunnerCandidates`, `PurviewSkillsCommand`, `PurviewSkillsPackage`, `PurviewSkillsAgents`, `PurviewSkillsSource`, `PurviewSkillsInstallRoot`, `PurviewSkillsRepoRoot`, -`PurviewSkillsUpdateMode`, `PurviewSkillsDryRun`, and the `PurviewSkillsAgentDirectory` item group. +`PurviewSkillsDryRun`, and the `PurviewSkillsAgentDirectory` item group. ## Compiler-visible properties @@ -163,6 +163,6 @@ Exported to analyzers and generators as `build_property.`: - `PurviewSuppressCopyRetryWarnings` - `PurviewSkillsSourceFolder`, `PurviewSkillsAgents`, `PurviewSkillsInstallRoot`, `PurviewRepositoryRootMarkers`, - `PurviewSkillsRunner`, `PurviewSkillsUpdateMode`, `PurviewSkillsDryRun` + `PurviewSkillsRunner`, `PurviewSkillsDryRun` - `PurviewBuildSdkVersionForGlobalJson`, `CurrentYear`, `AutoGeneratedAssemblyInfoFile`, `AutoGeneratedAssemblyIdentifierFile` diff --git a/skills/purview-buildsdk-repository-review/SKILL.md b/skills/purview-buildsdk-repository-review/SKILL.md index b4f56fa..2be4c08 100644 --- a/skills/purview-buildsdk-repository-review/SKILL.md +++ b/skills/purview-buildsdk-repository-review/SKILL.md @@ -101,7 +101,7 @@ reference that ships skills: - **Hand-written skill scripts** (`update-agent-skills.ts`, `ensure-universal-skills.ts`, `package.json` `skills:*` entries) are an incremental opportunity: the SDK targets replace them, and pin package skills to their package's commit where the scripts install latest. See - `purview-buildsdk-justfile`. + `purview-buildsdk-skills-justfile`. - **Drift**: run `dotnet msbuild -t:RecommendPurviewSkills` and quote any `PRSKL0010`/`PRSKL0011`. - **Layout**: if `PurviewSkillsAgents` is set, run `-t:CheckPurviewSkills` and quote any `PRSKL0015`. If it is not set, every agent directory is legitimate — that is acceptable variance, not a finding. diff --git a/skills/purview-buildsdk-skill-installation/SKILL.md b/skills/purview-buildsdk-skill-installation/SKILL.md index e5b93d6..5c2694d 100644 --- a/skills/purview-buildsdk-skill-installation/SKILL.md +++ b/skills/purview-buildsdk-skill-installation/SKILL.md @@ -10,7 +10,7 @@ metadata: # Installing the skills a package ships For *authoring* skills, use `purview-buildsdk-skill-tests`; for `just` recipes that run these -targets, `purview-buildsdk-justfile`. +targets, `purview-buildsdk-skills-justfile`. ## The one thing to understand first @@ -31,7 +31,7 @@ restore, a build, a design-time build or a test run. ```bash dotnet msbuild -t:ListPurviewSkills # diagnostics only, installs nothing dotnet msbuild -t:InstallPurviewSkills # delegates to the skills CLI -dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source, then 'skills update' +dotnet msbuild -t:UpdatePurviewSkills # re-add every skills-lock.json source: refresh, and add new skills dotnet msbuild -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist dotnet msbuild -t:FixPurviewSkills # remove the CLI's links from any other agent directory ``` @@ -46,7 +46,7 @@ Name **the solution**. Skills belong to the repository, so each target runs once projects the solution holds: every project hands the work to the same elected leader, and MSBuild runs it once. Package resolution reads every project in the solution, so a package only one project references is still found. A single project works too, but sees only its own packages. For `just` -recipes that run these targets, see `purview-buildsdk-justfile`. +recipes that run these targets, see `purview-buildsdk-skills-justfile`. ## How a skill is resolved, and why the version is always right @@ -69,21 +69,20 @@ dotnet restore dotnet msbuild -t:UpdatePurviewSkills ``` -`UpdatePurviewSkills` re-adds every unique source recorded in `skills-lock.json`, naming only the -skills the lockfile records for it: +`UpdatePurviewSkills` re-adds every unique source recorded in `skills-lock.json` with `skills add`: -- a source a restored package ships is re-added at **that package's commit** — the same pinned `add` - `PRSKL0011` recommends, so the skills match the package version referenced; -- every other source is re-added at its latest. +- a source a restored package ships is re-added at **that package's commit**, naming every skill + that package version ships — the same pinned `add` `PRSKL0011` recommends, so the skills match the + package version referenced; +- every other source is re-added at its latest with `--skill "*"`. -Then it runs `skills update -y -p`, which re-fetches each entry at the ref the lockfile records, so it -cannot undo a pin. `PurviewSkillsUpdateMode` decides when: `Auto` (default — only when the re-adds -changed the lockfile), `Always` or `Never`. `-p:PurviewSkillsDryRun=true` prints every command and -runs none. Each failed source is named (`PRSKL0008`) and `skills update` is then skipped. +That is the whole update. `skills add` reinstalls every skill it selects, so one re-add both +refreshes the installed skills and adds any the source has gained; `skills update` would only +re-fetch what the lockfile already lists, and is never run. `-p:PurviewSkillsDryRun=true` prints every +command and runs none. Each failed source is named (`PRSKL0008`). `InstallPurviewSkills` also works as an update for package skills alone: it re-adds each at its -package's commit, and the CLI skips one already at that ref. Do not reach for a bare -`skills update` instead; see below. +package's commit. Do not reach for a bare `skills update` instead; see below. ## Choosing agents @@ -133,9 +132,9 @@ The caller owns the ref here — append `#` to pin it. This path needs no r | `PRSKL0003` | No repository root resolved | Pass `-p:PurviewSkillsInstallRoot=` | | `PRSKL0004` | No skills CLI and no package runner found | Install Bun or Node, or set `PurviewSkillsCommand` | | `PRSKL0005` | An authored skill is malformed | See `purview-buildsdk-skill-tests` | -| `PRSKL0006` | `PurviewSkillsUpdateMode` is not `Auto`, `Always` or `Never` | Fix the value | +| `PRSKL0006` | Retired, with `PurviewSkillsUpdateMode` | Remove the property; update no longer runs `skills update` | | `PRSKL0007` | `UpdatePurviewSkills` found no `skills-lock.json` | Install first with `-t:InstallPurviewSkills` | -| `PRSKL0008` | Re-adding a lockfile source failed | Read the CLI output above it; `skills update` was skipped | +| `PRSKL0008` | Re-adding a lockfile source failed | Read the CLI output above it | | `PRSKL0009` | Install, update or fix was pulled into a build, a restore or a design-time build | Remove the hook; run the target on its own | | `PRSKL0010` | A skill a referenced package ships is missing | Warning. `bun x skills add ...` | | `PRSKL0011` | An installed skill is pinned to a different ref than the referenced package | Warning. Install the package's own commit | diff --git a/skills/purview-buildsdk-justfile/SKILL.md b/skills/purview-buildsdk-skills-justfile/SKILL.md similarity index 94% rename from skills/purview-buildsdk-justfile/SKILL.md rename to skills/purview-buildsdk-skills-justfile/SKILL.md index edab74a..2da36a2 100644 --- a/skills/purview-buildsdk-justfile/SKILL.md +++ b/skills/purview-buildsdk-skills-justfile/SKILL.md @@ -1,5 +1,5 @@ --- -name: purview-buildsdk-justfile +name: purview-buildsdk-skills-justfile description: Add or update Justfile recipes that run Purview.BuildSdk's agent-skill targets - skills-update, skills-check, skills-fix, skills-install, skills-recommend and skills-verify. Use when a repository wants a just recipe to update, install, check or clean up its agent skills, when replacing hand-written skill scripts (update-agent-skills.ts, ensure-universal-skills.ts, package.json skills:* scripts) with the SDK targets, or when an existing skills recipe runs the wrong project, the wrong runner or the wrong agents. license: MIT metadata: @@ -40,7 +40,7 @@ leave a placeholder: ```just skills_project := solution_file # or a path, when the Justfile has no such variable -# Update agent skills: re-add every skills-lock.json source, then 'skills update' +# Update agent skills: re-add every skills-lock.json source, refreshing installed skills and adding new ones [group('Agent skills')] skills-update *args: dotnet msbuild "{{ skills_project }}" "-t:UpdatePurviewSkills;FixPurviewSkills" -v:n {{ args }} @@ -135,7 +135,6 @@ Useful properties to pass through `*args`: | Property | Effect | | -- | -- | | `PurviewSkillsDryRun=true` | Print every CLI command; run none | -| `PurviewSkillsUpdateMode=Always` | Run `skills update` even when the lockfile did not change (`Auto` default, `Never`) | | `PurviewSkillsRunner=npx` | Launch the CLI through another runner (`bunx`, `pnpm`, `yarn`, `deno`) | | `PurviewSkillsSource=owner/repo#ref` | `skills-install` from an explicit source with no package behind it | @@ -146,7 +145,7 @@ Repositories often carry their own scripts for this. The SDK targets replace the | Hand-written | Replace with | | -- | -- | | `scripts/update-agent-skills.ts`, `"skills:update"` | `skills-update` (`UpdatePurviewSkills`) | -| `--update` / `--no-update` | `-p:PurviewSkillsUpdateMode=Always` / `Never` | +| `--update` / `--no-update` | Nothing: the re-add refreshes installed skills and adds new ones, so there is no separate `skills update` step to switch | | `--dry-run` | `-p:PurviewSkillsDryRun=true` | | `scripts/ensure-universal-skills.ts check`, `"skills:check"` | `skills-check` with `PurviewSkillsAgents=universal` | | `scripts/ensure-universal-skills.ts fix`, `"skills:fix"` | `skills-fix` | @@ -156,8 +155,9 @@ Two behaviours differ, deliberately — mention them when migrating: - A source a referenced package ships is re-added **at that package's commit**, not at latest, so its skills keep matching the package version. Other sources are re-added at latest, as before. -- Only the skills `skills-lock.json` records for a source are re-added, not `-s '*'`, so an update - never installs a skill nobody chose. +- Update is `skills add`, not `skills update`, so it also installs skills a source has **gained**: a + package source gets every skill its referenced version ships, and any other source is re-added with + `--skill "*"`. After switching, delete the scripts and their `package.json` entries, and remove `package.json` itself if nothing else uses it. Run `just skills-update -p:PurviewSkillsDryRun=true` and compare the diff --git a/src/src/BuildSdk/Sdk/Props/Defaults.props b/src/src/BuildSdk/Sdk/Props/Defaults.props index 543e70d..737b989 100644 --- a/src/src/BuildSdk/Sdk/Props/Defaults.props +++ b/src/src/BuildSdk/Sdk/Props/Defaults.props @@ -85,9 +85,6 @@ choose, and CheckPurviewSkills/FixPurviewSkills then enforce that only those agents' skill directories exist. --> - - Auto diff --git a/src/src/BuildSdk/Sdk/Sdk.props b/src/src/BuildSdk/Sdk/Sdk.props index 9907ed6..f150f83 100644 --- a/src/src/BuildSdk/Sdk/Sdk.props +++ b/src/src/BuildSdk/Sdk/Sdk.props @@ -413,9 +413,6 @@ Comma-separated agents the skill targets install to. Empty (the default) lets the skills CLI auto-detect; when set, CheckPurviewSkills and FixPurviewSkills allow only those agents' skill directories. - - When UpdatePurviewSkills runs 'skills update' after re-adding every lockfile source: Auto (only when skills-lock.json changed), Always or Never. Defaults to Auto. - When true, InstallPurviewSkills and UpdatePurviewSkills print the skills CLI commands without running them. diff --git a/src/src/BuildSdk/Sdk/Sdk.targets b/src/src/BuildSdk/Sdk/Sdk.targets index cf45960..e7adf63 100644 --- a/src/src/BuildSdk/Sdk/Sdk.targets +++ b/src/src/BuildSdk/Sdk/Sdk.targets @@ -990,20 +990,17 @@ - - - @@ -1030,7 +1024,6 @@ (); - LockFileHash = string.Empty; LockFileFound = File.Exists(LockFilePath); var lockText = string.Empty; @@ -1043,13 +1036,6 @@ if (LockFileFound) { - using (var sha = SHA256.Create()) - { - LockFileHash = string.Concat( - sha.ComputeHash(Encoding.UTF8.GetBytes(lockText)).Select(value => value.ToString("x2")) - ); - } - // Same reading as EvaluatePurviewSkillState: walk to the brace that closes the // 'skills' object, then one regex per flat entry. var namesBySource = new Dictionary>(StringComparer.OrdinalIgnoreCase); @@ -1112,11 +1098,10 @@ } else { + // Every skill the source has now, not just the ones recorded: re-adding is + // how an update picks up a skill the source has gained since. created = new TaskItem(pair.Key); - created.SetMetadata( - "Skills", - string.Join(";", pair.Value.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)) - ); + created.SetMetadata("Skills", "*"); created.SetMetadata("Origin", "skills-lock.json"); } @@ -2914,8 +2899,8 @@ Text="No restored package ships installable agent skills. Run -t:ListPurviewSkills for detail." /> - $([MSBuild]::NormalizePath('$(_PurviewSkillsRepositoryRoot)', 'skills-lock.json')) - Auto - - - + - - <_PurviewSkillsUpdateFailed Condition="'@(_PurviewSkillsUpdateFailure)' != ''" - >true - - - - <_PurviewSkillsUpdateCommand>$(PurviewSkillsCommand) update -y -p - - - - - - - <_PurviewSkillsRunUpdate>false - <_PurviewSkillsRunUpdate Condition="'$(PurviewSkillsUpdateMode)' == 'Always'">true - <_PurviewSkillsRunUpdate - Condition="'$(PurviewSkillsUpdateMode)' == 'Auto' AND '$(_PurviewSkillsLockHashAfter)' != '$(_PurviewSkillsLockHashBefore)'" - >true - - - - - @@ -3390,7 +3327,7 @@ -t:RecommendPurviewSkills report the state, never fail -t:VerifyPurviewSkills the same state, as a build failure -t:InstallPurviewSkills install or update, pinned to each package's commit - -t:UpdatePurviewSkills re-add every lockfile source, then 'skills update' + -t:UpdatePurviewSkills re-add every lockfile source: refresh, and add new skills -t:CheckPurviewSkills only the selected agents' skill directories exist -t:FixPurviewSkills remove the CLI's links from any other agent directory -t:ListPurviewSkills what the restored packages ship diff --git a/src/tests/BuildSdk.IntegrationTests/PurviewSkillUpdateTests.cs b/src/tests/BuildSdk.IntegrationTests/PurviewSkillUpdateTests.cs index 81efdbc..568ca42 100644 --- a/src/tests/BuildSdk.IntegrationTests/PurviewSkillUpdateTests.cs +++ b/src/tests/BuildSdk.IntegrationTests/PurviewSkillUpdateTests.cs @@ -76,13 +76,17 @@ public async Task Update_ReAddsEachSource_PinningThePackagesOwnCommit(Cancellati await Assert .That(output) .Contains($"add \"{PackageSource}#{SkillPackageFixtures.DefaultCommit}\" --skill \"purview-alpha\""); - // Every other source is re-added once, naming only the skills the lockfile records for it. - await Assert.That(output).Contains($"add \"{OtherSource}\" --skill \"frontend-design\" --skill \"web-design\""); + // Every other source is re-added once, with every skill it has, so a skill the repository has + // gained since the last install comes in too. + await Assert.That(output).Contains($"add \"{OtherSource}\" --skill \"*\""); + await Assert.That(output).DoesNotContain("--skill \"web-design\""); await Assert.That(output).DoesNotContain(OldCommit + "\" --skill"); // No agents named: the CLI auto-detects, so no agent flag is passed. await Assert.That(output).DoesNotContain("--agent"); - // 'echo' leaves the lockfile untouched, so Auto skips 'skills update'. - await Assert.That(output).Contains("skipped 'echo update -y -p'"); + // The re-adds are the whole update: 'skills add' refreshes installed skills and adds new ones, + // so 'skills update' is never run. + await Assert.That(output).Contains("2 source(s) refreshed."); + await Assert.That(output).DoesNotContain("echo update"); } [Test] @@ -106,21 +110,31 @@ public async Task Update_NamedAgents_BecomeOneFlagEach(CancellationToken cancell } [Test] - public async Task Update_ModeAlways_RunsSkillsUpdate(CancellationToken cancellationToken) + public async Task Update_AddsASkillThePackageHasGained(CancellationToken cancellationToken) { using var harness = await ProjectHarness.CreateAsync("SkillUpdate", cancellationToken: cancellationToken); GivenInstalledSkills(harness); + // The referenced version now ships a second skill the lockfile has never recorded. + SkillPackageFixtures.WritePackage( + Path.Combine(harness.SolutionDirectory, "packages"), + PackageId, + PackageVersion, + ["purview-alpha", "purview-beta"] + ); var (code, output) = await RunAsync( harness, "UpdatePurviewSkills", - "-p:PurviewSkillsCommand=echo -p:PurviewSkillsUpdateMode=Always", + "-p:PurviewSkillsCommand=echo", cancellationToken ); await Assert.That(code).IsZero().Because(output); - await Assert.That(output).Contains("Agent skills: echo update -y -p"); - await Assert.That(output).Contains("refreshed and updated"); + await Assert + .That(output) + .Contains( + $"add \"{PackageSource}#{SkillPackageFixtures.DefaultCommit}\" --skill \"purview-alpha\" --skill \"purview-beta\"" + ); } [Test] @@ -143,7 +157,7 @@ public async Task Update_DryRun_RunsNothing(CancellationToken cancellationToken) } [Test] - public async Task Update_AFailedSource_IsNamed_AndSkillsUpdateIsSkipped(CancellationToken cancellationToken) + public async Task Update_EveryFailedSource_IsNamed(CancellationToken cancellationToken) { using var harness = await ProjectHarness.CreateAsync("SkillUpdate", cancellationToken: cancellationToken); GivenInstalledSkills(harness); @@ -152,7 +166,7 @@ public async Task Update_AFailedSource_IsNamed_AndSkillsUpdateIsSkipped(Cancella var (code, output) = await RunAsync( harness, "UpdatePurviewSkills", - "\"-p:PurviewSkillsCommand=dotnet purview-no-such-command\" -p:PurviewSkillsUpdateMode=Always", + "\"-p:PurviewSkillsCommand=dotnet purview-no-such-command\"", cancellationToken ); @@ -160,7 +174,7 @@ public async Task Update_AFailedSource_IsNamed_AndSkillsUpdateIsSkipped(Cancella await Assert.That(output).Contains("PRSKL0008"); await Assert.That(output).Contains($"re-adding '{OtherSource}' failed"); await Assert.That(output).Contains($"re-adding '{PackageSource}#{SkillPackageFixtures.DefaultCommit}' failed"); - await Assert.That(output).DoesNotContain("Agent skills: dotnet purview-no-such-command update"); + await Assert.That(output).DoesNotContain("source(s) refreshed."); } [Test] diff --git a/templates/global.json b/templates/global.json index 4cf8f53..77535b3 100644 --- a/templates/global.json +++ b/templates/global.json @@ -3,6 +3,6 @@ "runner": "Microsoft.Testing.Platform" }, "msbuild-sdks": { - "Purview.BuildSdk": "1.3.1" + "Purview.BuildSdk": "1.3.2" } }