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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

### Fixed

- Run native Windows skill updates from the caller's project directory instead of the `updates` installation directory, for both direct and `npx` execution.
- Make Unix command and capture waits interruptible, preserve interactive stdin and exit statuses, and clean owned children, output helpers, and temporary resources on SIGINT/SIGTERM.
- Disable prompts for background pip installations and for discovery/planning under `--non-interactive`.
- Honor `--non-interactive` for Homebrew upgrade-table confirmation with command-scoped `HOMEBREW_NO_ASK=1`; explain the confirmation prompt during interactive runs.
Expand Down
15 changes: 9 additions & 6 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@

## Execution checklist

- [ ] Register a default-on `skills` module between `pi` and `mise` on Bash and native Windows.
- [ ] Resolve the backing command as the `skills` CLI first, then `npx --yes skills`; skip gracefully when neither exists and fail under `--only`.
- [ ] Run `skills update --project --global`, appending `--yes` under `--non-interactive`; dry-run prints the resolved command without executing.
- [ ] Cover direct, npx-fallback, non-interactive, dry-run, and missing-dependency behavior in Bash tests; mirror success, fallback, and missing-dependency coverage in native Windows tests.
- [ ] Update README, SPEC (module matrix, execution order, §8.15), CHANGELOG, and this plan.
- [ ] Pass lint and tests before opening the PR.
- [x] Register a default-on `skills` module between `pi` and `mise` on Bash and native Windows.
- [x] Resolve the backing command as the `skills` CLI first, then `npx --yes skills`; skip gracefully when neither exists and fail under `--only`.
- [x] Run `skills update --project --global`, appending `--yes` under `--non-interactive`; dry-run prints the resolved command without executing.
- [x] Cover direct, npx-fallback, non-interactive, dry-run, and missing-dependency behavior in Bash tests; mirror success, fallback, and missing-dependency coverage in native Windows tests.
- [x] Preserve the caller's project directory on native Windows and cover project paths containing spaces on both platforms.
- [x] Update README, SPEC (module matrix, execution order, §8.15), CHANGELOG, and this plan.
- [x] Pass lint and full local tests; record native Windows validation availability.

Validation: `./scripts/lint.sh`, `./scripts/test.sh`, and the focused skills tests under `/bin/bash` passed on macOS. An isolated PowerShell handler check reproduced the wrong working directory before the fix and passed for direct/npx adapters afterward. Native Windows execution remains unverified on this host; all skill update commands were stubbed.

---

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ updates --dry-run
updates --only brew,node --brew-mode formula
updates --only linux -n
updates --only winget,node,bun
updates --only skills -n
updates --full
updates --skip python --log-file ./updates.log
updates --json -n --no-self-update --log-level warn
Expand Down Expand Up @@ -101,7 +102,7 @@ Modules are auto-detected: if the underlying command isn’t installed, the modu
- `rustup`: update Rust toolchains via `rustup update`
- `claude`: update Claude Code CLI via `claude update`
- `pi`: update the pi AI CLI and installed extensions via `pi update --all`
- `skills`: update agent skills in both project and global scopes via `skills update` (falls back to `npx --yes skills update`); passing both scopes matches the interactive "Both" option without prompting
- `skills`: update agent skills in both project and global scopes via `skills update --project --global` (falls back to `npx --yes skills update --project --global`); project scope uses the directory where you run `updates`, not all projects on the machine
- `mise`: update mise and upgrade installed tools (`mise self-update`, `mise upgrade`)
- `go`: update Go binaries from `GO_BINARIES` in `~/.updatesrc` (entries default to `@latest`)
- `macos`: list available macOS software updates via `softwareupdate -l` (disabled by default; enable with `--macos-updates` or `--full`)
Expand Down
5 changes: 3 additions & 2 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,12 +573,13 @@ Purpose: update the `pi` AI coding CLI and its installed extensions (pinned sour

### 8.15 `skills`

Purpose: update agent skills installed on the machine in both project and global scopes.
Purpose: update agent skills in the caller's current project directory and global scope. This does not scan other projects on the machine.

- Requires: the `skills` CLI (`npx skills`), or `npx` as a fallback adapter.
- Resolution order: a direct `skills` command on `PATH` first, then `npx --yes skills`.
- If neither is available, default runs warn and skip; explicit `--only skills` fails.
- If neither is available, default runs log and skip; explicit `--only skills` fails.
- Scope: runs `skills update --project --global`, which the skills CLI resolves to its interactive "Both" scope without prompting.
- Working directory: preserve the caller's directory on Bash and native Windows, including when using the `npx` fallback; never substitute the `updates` installation directory.
- Non-dry-run:
- Bash: `<skills|npx --yes skills> update --project --global [--yes]`
- Native Windows: `skills update --project --global` or `npx --yes skills update --project --global`
Expand Down
9 changes: 9 additions & 0 deletions tests/test_cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1779,6 +1779,15 @@ write_stub npx 'echo "npx $*" >>"$CALL_LOG"'
out="$("$SCRIPT" --only skills --no-emoji --no-color)"
echo "$out" | grep -q '^==> skills END (OK)'
grep -q '^npx --yes skills update --project --global$' "$CALL_LOG"
skills_project="${tmp_dir}/skills project"
mkdir -p "$skills_project"
# shellcheck disable=SC2016
write_stub npx 'echo "npx $*" >>"$CALL_LOG"; pwd -P >>"$CALL_LOG"'
: >"$CALL_LOG"
out="$(cd "$skills_project" && "$SCRIPT" -n --only skills --no-emoji --no-color)"
echo "$out" | grep -q '^==> skills END (OK)'
grep -q '^npx --yes skills update --project --global --yes$' "$CALL_LOG"
grep -Fxq "$(cd "$skills_project" && pwd -P)" "$CALL_LOG"
: >"$CALL_LOG"
out="$("$SCRIPT" --dry-run --only skills --no-emoji --no-color)"
echo "$out" | grep -q '^DRY RUN: npx --yes skills update --project --global$'
Expand Down
19 changes: 15 additions & 4 deletions tests/test_windows_native.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2193,12 +2193,19 @@ if (Should-RunTest 'native payload runs Skills update module') {
Install-RepoWindowsRuntime -RepoRoot $repoRoot -InstallRoot $installRoot -Version $currentReleaseVersion
$stubDir = Join-Path $installRoot 'stubs'
$log = Join-Path $installRoot 'skills-module.log'
$projectDir = Join-Path $installRoot 'project with spaces'
$cwdLog = Join-Path $installRoot 'skills-cwd.log'
$null = New-Item -ItemType Directory -Path $stubDir -Force
Write-CmdStub -Path (Join-Path $stubDir 'skills.cmd') -Lines @(('echo skills:%*>>"{0}"' -f $log))
$result = Invoke-Bootstrap -InstallRoot $installRoot -ArgumentList @('--no-self-update', '--only', 'skills', '--no-emoji', '--no-color') -Environment @{ PATH = $stubDir }
$null = New-Item -ItemType Directory -Path $projectDir -Force
Write-CmdStub -Path (Join-Path $stubDir 'skills.cmd') -Lines @(
('echo skills:%*>>"{0}"' -f $log),
('cd >"{0}"' -f $cwdLog)
)
$result = Invoke-ProcessCapture -FilePath (Get-PwshPath) -ArgumentList @('-NoLogo', '-NoProfile', '-File', (Join-Path $installRoot 'updates.ps1'), '--no-self-update', '--only', 'skills', '--no-emoji', '--no-color') -WorkingDirectory $projectDir -Environment @{ PATH = $stubDir }
Assert-Equal -Expected 0 -Actual $result.ExitCode -Message "Skills module should succeed`n$($result.Output)"
$calls = Get-Content -LiteralPath $log -Raw
Assert-Match -Text $calls -Pattern '(?m)^skills:update --project --global\s*$' -Message 'Skills module should update project and global scopes without prompting'
Assert-Equal -Expected $projectDir -Actual (Get-Content -LiteralPath $cwdLog -Raw).Trim() -Message 'Skills should run from the caller project, not the updates installation'

$emptyPath = Join-Path $installRoot 'empty-skills-path'
$null = New-Item -ItemType Directory -Path $emptyPath -Force
Expand All @@ -2207,12 +2214,16 @@ if (Should-RunTest 'native payload runs Skills update module') {
Assert-Match -Text $missing.Output -Pattern '(?i)skills not found' -Message 'missing Skills dependency should be explicit'

$npxLog = Join-Path $installRoot 'skills-npx.log'
Write-CmdStub -Path (Join-Path $stubDir 'npx.cmd') -Lines @(('echo npx:%*>>"{0}"' -f $npxLog))
Write-CmdStub -Path (Join-Path $stubDir 'npx.cmd') -Lines @(
('echo npx:%*>>"{0}"' -f $npxLog),
('cd >"{0}"' -f $cwdLog)
)
Remove-Item -LiteralPath (Join-Path $stubDir 'skills.cmd') -Force
$fallback = Invoke-Bootstrap -InstallRoot $installRoot -ArgumentList @('--no-self-update', '--only', 'skills', '--non-interactive', '--no-emoji', '--no-color') -Environment @{ PATH = $stubDir }
$fallback = Invoke-ProcessCapture -FilePath (Get-PwshPath) -ArgumentList @('-NoLogo', '-NoProfile', '-File', (Join-Path $installRoot 'updates.ps1'), '--no-self-update', '--only', 'skills', '--non-interactive', '--no-emoji', '--no-color') -WorkingDirectory $projectDir -Environment @{ PATH = $stubDir }
Assert-Equal -Expected 0 -Actual $fallback.ExitCode -Message "Skills npx fallback should succeed`n$($fallback.Output)"
$npxCalls = Get-Content -LiteralPath $npxLog -Raw
Assert-Match -Text $npxCalls -Pattern '(?m)^npx:--yes skills update --project --global --yes\s*$' -Message 'npx fallback should update both scopes non-interactively'
Assert-Equal -Expected $projectDir -Actual (Get-Content -LiteralPath $cwdLog -Raw).Trim() -Message 'npx skills should retain the caller project directory'
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion updates-main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,7 @@ function Invoke-ModuleSkills {
$arguments.Add('--yes')
}

$result = Invoke-LoggedProcess -FilePath $filePath -ArgumentList $arguments.ToArray()
$result = Invoke-LoggedProcess -FilePath $filePath -ArgumentList $arguments.ToArray() -WorkingDirectory (Get-Location).Path
if ($result.ExitCode -ne 0) {
Write-ErrorLine 'skills: update failed'
return 1
Expand Down