Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
09f6b6d
feat(shell): add shell settings contracts and cached-state UI binding
Jul 28, 2026
19a3dbf
fix(shell): add terminal shell settings translations to all 17 locales
Jul 28, 2026
ac0ed1b
fix(settings): restore mode-based cachedState sync reverted in B04 re…
Jul 28, 2026
a68ac23
feat(terminal): add unified shell resolution system (B05)
Aug 2, 2026
683b1e0
fix(task): remove BOM character from Task.ts causing invisible-chars …
Aug 2, 2026
4dc9610
fix(lint): update eslint-suppressions for B05 test files - add entrie…
Aug 2, 2026
28847b3
fix(terminal): use vscode provider for non-cmd shells in CommandEnvir…
Aug 2, 2026
0e63b22
fix(terminal): resolve B05 lifecycle and cross-platform CI failures
Aug 2, 2026
83e7e38
fix(terminal): pass profile shellArgs to VS Code terminal + restore m…
Aug 2, 2026
fae94c7
fix(terminal): guard illegal integration-ready self-transition + mock…
Aug 2, 2026
f851635
fix(terminal): respect static Terminal.getTerminalProfile() in comman…
Aug 2, 2026
b760a0d
fix(api): use optional call for getCommandEnvironmentService in setTe…
Aug 2, 2026
bc28103
test(e2e): raise shell-integration timeout to 30s in terminal-profile…
Aug 2, 2026
c08701f
fix(api): add runtime setShellIntegrationTimeout + apply it in termin…
Aug 2, 2026
9c3fd51
test(e2e): retry Terminal Profile suite on CI shell-integration flake
Aug 2, 2026
82d31f4
fix(terminal): use shell-integration-compatible profile in E2E test (…
Aug 2, 2026
9a5e2ae
fix(terminal): use shell-integration-safe --login arg in E2E test
Aug 2, 2026
60c5c77
fix(shell): mark settings dirty on shell selection change
Aug 3, 2026
35cc3dc
Merge branch 'pr/b04-shell-contracts-v2' into pr/b05-shell-resolution-v2
Aug 3, 2026
0f627a9
fix(ci): make RooTerminal lifecycle optional; ignore B06 scaffolding …
Aug 2, 2026
fcc3f09
fix(ci): add @types/shell-quote to dependencies
Aug 2, 2026
47e4687
fix(ci): resolve knip and check-types failures - exclude playwright, …
Aug 2, 2026
b2eef0b
fix(terminal): revert lifecycle/canReuse to required in RooTerminal i…
Aug 2, 2026
502e7df
chore: remove docs contamination and revert knip.json warn->off rules
Aug 4, 2026
bf2d780
chore: remove docs and scripts contamination
Aug 4, 2026
f033ccc
chore: remove temp file progress.txt
Aug 6, 2026
14f7617
feat: add local-ci-precheck skill for pre-push CI verification
Aug 6, 2026
2335da1
Merge branch 'main' into pr/b06-terminal-lifecycle-v2
myk1yt Aug 7, 2026
1c9e578
test(e2e): add terminal lifecycle suite
Aug 7, 2026
57bbae1
fix(test): stop infinite fixture loop in terminal-lifecycle e2e (PR #…
Aug 8, 2026
065f8f6
fix(vscode-e2e): attach TaskAborted listener before triggering cancel…
Aug 8, 2026
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
304 changes: 304 additions & 0 deletions .roo/skills/local-ci-precheck/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
---
name: local-ci-precheck
description: Pre-push CI check skill that runs 7 local CI checks (invisible characters, translations, ESLint, TypeScript, knip, unit tests, webview visual) before git push. Prevents CI failures by catching errors locally in ~5 minutes instead of waiting for GitHub Actions. Use when about to git push in the Zoo Code project.
---

# Local CI Pre-check Skill

## When to Use This Skill

Use this skill when:

- Code mode or Light-Code mode is about to `git push` in the Zoo Code project
- You want to verify that all locally-runnable CI checks pass before pushing
- You want to catch lint errors, type errors, test failures, and dead code before CI

## When NOT to Use This Skill

Do NOT use this skill when:

- The user explicitly passes `--skip-ci-check`
- Only non-source files changed (e.g., only `.md`, `.json` config files, `.yml` workflow files with no logic changes)
- Pushing to a branch that does not have CI enabled

## Pre-conditions

Before running checks, verify:

1. Node.js is installed (`node --version`)
2. Dependencies are installed (`corepack pnpm install`)
3. Working directory is the Zoo Code project root

## Checks (Sequential, Fastest-First Order)

Run all 7 checks in order. **Stop at the first failure** and report. Each check includes Windows (PowerShell) and Linux/Mac (bash) commands.

---

### Check 1: Invisible Characters (~2s)

Detect zero-width characters, directional overrides, BOM, and soft hyphens that can cause subtle bugs.

**Windows (PowerShell):**
```powershell
$patterns = '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]'
Get-ChildItem -Recurse -Include *.ts,*.tsx,*.js,*.mjs,*.cjs,*.cts,*.mts,*.sh,*.yml,*.yaml -Exclude node_modules,dist,out,coverage,.turbo,.vinxi -Path src,webview-ui,packages,apps,.github |
Select-String -Pattern $patterns |
ForEach-Object { Write-Host "FOUND: $($_.Filename):$($_.LineNumber): $($_.Line)" }
```

**Linux/Mac (bash):**
```bash
grep -rnP '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' \
--include='*.ts' --include='*.tsx' --include='*.js' --include='*.mjs' \
--include='*.cjs' --include='*.cts' --include='*.mts' --include='*.sh' \
--include='*.yml' --include='*.yaml' \
--exclude-dir=node_modules --exclude-dir=dist --exclude-dir=out \
--exclude-dir=coverage --exclude-dir=.turbo --exclude-dir=.vinxi \
src webview-ui packages apps .github
```

**Pass criteria:** No output (exit code 0).
Comment on lines +42 to +61

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set +e

printf '\u200b\n' | grep -P '[\x{200B}]' >/dev/null 2>&1
printf 'grep -P exit code: %s\n' "$?"

if command -v pwsh >/dev/null 2>&1; then
  pwsh -NoProfile -Command \
    'try { [regex]::new("[\x{200B}]") | Out-Null; exit 0 } catch { exit 1 }'
  printf 'PowerShell regex exit code: %s\n' "$?"
fi

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 210


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf 'Repository files matching SKILL.md:\n'
fd -a 'SKILL\.md$' .roo/skills/local-ci-precheck 2>/dev/null || true

if [ -f .roo/skills/local-ci-precheck/SKILL.md ]; then
  echo
  echo 'Relevant lines:'
  sed -n '1,90p' .roo/skills/local-ci-precheck/SKILL.md | cat -n
fi

echo
echo 'PowerShell availability:'
command -v pwsh || true
if command -v pwsh >/dev/null 2>&1; then
  pwsh --version 2>&1 | head -n 1
  echo
  echo 'PowerShell regex validation and matching probes:'
  pwsh -NoProfile -Command '
    $patterns = @("[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]","[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]")
    foreach ($p in $patterns) {
      try {
        [regex]::new($p) > $null
        Write-Host "Pattern OK: $p"
      } catch {
        Write-Host "Pattern FAIL: $p"
      }
    }
    $file = New-TemporaryFile
    [IO.File]::WriteAllText($file.FullName, "abc `u200b xyz", $PSDefaultParameterValues["Out-File:Encoding"] = "utf8NoBOM")
    $output = Select-String -Path $file.FullName -Pattern "[\u200B]"
    Write-Host "Select-String match count: $($output.Count)"
    Write-Host "Select-String line: $($output[0].Line.Trim("`t"))"
    $lastline = $output[0].Line
    Write-Host "Hidden code points in last line: $(foreach ($c in $lastline.ToCharArray()) [string]::Format(`"0x$($_.ToString(`"x4`"))")) )"
    Remove-Item $file.FullName
  '
fi

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 4598


🏁 Script executed:

#!/usr/bin/env bash
set -u

echo 'PowerShell regex validation and matching probes'
pwsh -NoProfile -Command '
  $patterns = @("[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]","[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]")
  foreach ($p in $patterns) {
    try {
      [regex]::new($p) > $null
      Write-Host "Pattern OK: $p"
    } catch {
      Write-Host "Pattern FAIL: $p"
    }
  }
  $file = New-TemporaryFile
  $bytes = [System.Text.Encoding]::UTF8.GetBytes("abc `u200b xyz")
  [IO.File]::WriteAllBytes($file.FullName, $bytes)
  $output = Select-String -Path $file.FullName -Pattern "[\u200B]" -Encoding UTF8
  Write-Host "Select-String match count: $($output.Count)"
  if ($output.Count -gt 0) {
    Write-Host "Select-String line: " -NoNewline
    Write-Host $output[0].Line.Replace("`u200b", "`u200B") -NoNewline
    Write-Host " | codepoints: " -NoNewline
    foreach ($c in $output[0].Line.ToCharArray()) {
      Write-Host ("0x" + [System.String]::Format("x4", [int]$c) + " ") -NoNewline
    }
  }
  Remove-Item $file.FullName
'

echo
echo 'Check grep -P behavior on hidden character file'
python3 - <<'PY'
from pathlib import Path
import subprocess, sys, tempfile

p = Path(tempfile.mktemp())
p.write_bytes("abc \u200b xyz".encode("utf-8"))
out = subprocess.run(["grep", "-P", "[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]", "-n", str(p)], capture_output=True, text=True)
print("grep -P exit_code=", out.returncode, "matches=", bool(out.stdout))
if out.stderr:
    print("stderr=", out.stderr.rstrip())
print("output=", repr(out.stdout))
PY

echo
echo 'Check grep available options without PCRE'
command -v rg || true
command -v fd || true

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1006


🏁 Script executed:

#!/usr/bin/env bash
set -u

echo 'PowerShell regex validation and matching probes'
pwsh -NoProfile -Command '
  $patterns = @("[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]","[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]")
  foreach ($p in $patterns) {
    try {
      [regex]::new($p) > $null
      Write-Host "Pattern OK: $p"
    } catch {
      Write-Host "Pattern FAIL: $p"
    }
  }
  $file = New-TemporaryFile
  $bytes = [System.Text.Encoding]::UTF8.GetBytes(("abc " + [char]0x200B + " xyz"))
  [IO.File]::WriteAllBytes($file.FullName, $bytes)
  $output = Select-String -Path $file.FullName -Pattern "[\u200B]" -Encoding UTF8
  Write-Host "Select-String match count: $($output.Count)"
  if ($output.Count -gt 0) {
    Write-Host "Select-String line: " -NoNewline
    Write-Host $output[0].Line.Replace((ConvertFrom-UShort $charArray = [char]0x200B; ConvertTo-UShort ([System.Enum]::ToObject([char], $charArray[0]))), (ConvertTo-UShort ([System.Enum]::ToObject([char],0x200B)))) -NoNewline
    Write-Host " | codepoints: " -NoNewline
    foreach ($c in $output[0].Line.ToCharArray()) {
      Write-Host ("0x" + [System.String]::Format("x4", [int]$c) + " ") -NoNewline
    }
  }
  Remove-Item $file.FullName
'

echo
echo 'PowerShell regex validation and matching probes alternative'
pwsh -NoProfile mpsa-regex.txt - <<'PSC'
$patterns = @("[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]","[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]")
foreach ($p in $patterns) {
  try {
    [regex]::new($p) > $null
    Write-Host "Pattern OK: $p"
  } catch {
    Write-Host "Pattern FAIL: $p"
  }
}
$file = New-TemporaryFile
$bytes = [System.Text.Encoding]::UTF8.GetBytes(("abc " + [char]0x200B + " xyz"))
[IO.File]::WriteAllBytes($file.FullName, $bytes)
$output = Select-String -Path $file.FullName -Pattern "[\u200B]" -Encoding UTF8
Write-Host "Select-String match count: $($output.Count)"
if ($output.Count -gt 0) {
  Write-Host "Select-String line: " -NoNewline
  Write-Host $output[0].Line.Replace([char]0x200B, [char]0x200B) -NoNewline
  Write-Host " | codepoints: " -NoNewline
  foreach ($c in $output[0].Line.ToCharArray()) {
    Write-Host ("0x" + [System.String]::Format("x4", [int]$c) + " ") -NoNewline
  }
}
Remove-Item $file.FullName
PSC

echo
echo 'Check grep -P behavior on hidden character file'
tmp="$(mktemp)"
printf 'abc \u200b xyz' > "$tmp"
grep -P '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "$tmp" >/dev/null 2>&1
printf 'grep -P exit_code=%s has_match=%s\n' "$?" "$($tmp; if grep -P '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' "$tmp" >/dev/null 2>&1; then echo true; else echo false; fi)"
rm -f "$tmp"

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1786


🏁 Script executed:

#!/usr/bin/env bash
set -u

echo 'PowerShell regex validation and matching probes'
pwsh -NoProfile -Command '
  $invisible = [char]0x200B
  $patterns = @("[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]","[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]")
  foreach ($p in $patterns) {
    try {
      [regex]::new($p) > $null
      Write-Host "Pattern OK: $p"
    } catch {
      Write-Host "Pattern FAIL: $p"
    }
  }
  $file = New-TemporaryFile
  [IO.File]::WriteAllText($file.FullName, [("abc " + $invisible + " xyz")], [Text.Encoding]::UTF8)
  $output = Select-String -Path $file.FullName -Pattern "[\u200B]" -Encoding UTF8
  Write-Host "Select-String match count: $($output.Count)"
  if ($output.Count -gt 0) {
    Write-Host "Select-String line: " -NoNewline
    Write-Host ($output[0].Line.Replace($invisible, [char]0x200B)) -NoNewline
    Write-Host " | codepoints: " -NoNewline
    foreach ($c in $output[0].Line.ToCharArray()) {
      Write-Host ("0x" + [System.String]::Format("x4", $([int]$c))) -NoNewline
    }
    Write-Host ""
  }
  Remove-Item $file.FullName
'

echo
echo 'grep -P pattern syntax probe'
tmp="$(mktemp)"
printf 'abc %b xyz' "$(printf '\342\200\213')" > "$tmp"
printf 'text\n' > "${tmp}.clean"
if grep -P '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "$tmp" >/dev/null 2>&1; then
  echo 'temp: grep -P found invisible char'
else
  echo 'temp: grep -P did not find invisible char; status='$?
fi
if grep -P '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "${tmp}.clean" >/dev/null 2>&1; then
  echo 'clean: grep -P found invisible char'
else
  echo 'clean: grep -P did not find invisible char; status='$?
fi
rm -f "$tmp" "${tmp}.clean"

echo
echo 'PowerShell Select-String output status probe'
pwsh -NoProfile -Command '
  $invisible = [char]0x200B
  $file = New-TemporaryFile
  [IO.File]::WriteAllText($file.FullName, [("abc " + $invisible + " xyz")], [Text.Encoding]::UTF8)
  Set-Variable -Name _last -Value (Select-String -Path $file.FullName -Pattern "[\u200B]" -Encoding UTF8) -Scope Script
  Remove-Item $file.FullName
  Write-Host "Found matches: $($null -ne $_last -and $_last.Count -gt 0)"
'

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 768


🏁 Script executed:

#!/usr/bin/env bash
set -u

echo 'grep -P pattern syntax probe'
tmp="$(mktemp)"
printf 'abc %b xyz' "$(printf '\342\200\213')" > "$tmp"
printf 'text\n' > "${tmp}.clean"
set +e
grep -P $'[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "$tmp" >/dev/null 2>&1
printf 'temp: exit=%s matches=%s\n' "$?" "$([ "$(grep -P $'[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "$tmp" 2>/dev/null)" ] && echo true || echo false)"
grep -P $'[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "${tmp}.clean" >/dev/null 2>&1
printf 'clean: exit=%s matches=%s\n' "$?" "$([ "$(grep -P $'[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]' -n "${tmp}.clean" 2>/dev/null)" ] && echo true || echo false)"
set -e
rm -f "$tmp" "${tmp}.clean"

echo
echo 'PowerShell regex validation probe'
pwsh -NoProfile <<'PSH'
$invisible = [char]0x200B
$patterns = @('[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}\x{FEFF}\x{00AD}]','[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD]')
foreach ($p in $patterns) {
  try {
    [regex]::new($p) > $null
    Write-Host "Pattern OK: $p"
  } catch {
    Write-Host "Pattern FAIL: $p"
  }
}
$file = New-TemporaryFile
[System.IO.File]::WriteAllText($file.FullName, "abc " + $invisible + " xyz", [Text.Encoding]::UTF8)
$output = Select-String -Path $file.FullName -Pattern '[\u200B]' -Encoding UTF8
Write-Host "Select-String match count: $($output.Count)"
[System.IO.File]::WriteAllText($file.FullName, "abc clean xyz", [Text.Encoding]::UTF8)
$outputClean = Select-String -Path $file.FullName -Pattern $invisible -Encoding UTF8
Write-Host "Select-String clean match count: $($outputClean.Count)"
[System.IO.File]::WriteAllText($file.FullName, "abc " + $invisible + " xyz", [Text.Encoding]::UTF8)
$matches = @()
Select-String -Path $file.FullName -Pattern $("$invisible") -Encoding UTF8 | ForEach-Object { $matches += $_ }
Write-Host "Pipeline matched lines: $($matches.Count)"
[System.IO.File]::WriteAllText($file.FullName, "abc clean xyz", [Text.Encoding]::UTF8)
>Select-String -Path $file.FullName -Pattern $("$invisible") -Encoding UTF8
if ($LASTEXITCODE) {
  Write-Host "LASTEXITCODE=$LASTEXITCODE"
} else {
  Write-Host "LASTEXITCODE=$LASTEXITCODE"
}
Remove-Item $file.FullName
PSH

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1837


🌐 Web query:

PowerShell Select-String exit code behavior when matches found

💡 Result:

The Select-String cmdlet does not return an exit code [1][2]. It is a native PowerShell cmdlet, and its behavior is defined by the objects it outputs to the pipeline, not by process exit codes [1][3]. By default, Select-String returns MatchInfo objects when matches are found [1][4]. If no matches are found, it outputs nothing (null) [1][4]. When the -Quiet parameter is used, the cmdlet returns a Boolean value ($true if matches are found, or $null/false if no matches are found) [1][2][3]. Because Select-String does not set an exit code, you cannot check it using the standard $LASTEXITCODE variable (which is intended for external executable commands) [5]. To detect whether a match was found in a script, you should instead evaluate the output of the command directly [5][6]. For example: if (Select-String -Path "file.txt" -Pattern "pattern" -Quiet) { Write-Host "Match found" } else { Write-Host "No match found" } If you need to force an exit code in a script based on the results of Select-String, you must manually trigger it using the exit command [5]. # Example of manual exit code handling $result = Select-String -Path "file.txt" -Pattern "error" if ($result) { exit 1 } else { exit 0 }

Citations:


🌐 Web query:

grep -P PCRE Unicode code point \x{...} pattern example

💡 Result:

In PCRE (Perl-Compatible Regular Expressions), such as those used by grep -P, Unicode characters can be specified using the hexadecimal escape sequence \x{...} [1][2][3]. Syntax and Usage The \x{...} syntax allows you to specify a Unicode code point by its hexadecimal value [1][3]. The braces are necessary when specifying code points that require more than two hexadecimal digits, or simply for clarity [1][4][5]. Example To match a character by its specific Unicode code point, you can use the following pattern: grep -P '\x{3b1}' file.txt This command will search for the Greek letter "alpha" (U+03B1) in file.txt [3]. Key Requirements 1. Unicode Mode: For these patterns to work correctly with Unicode characters, the grep implementation must be operating in a mode that supports UTF/Unicode [4][6]. When using grep -P, it is often necessary to ensure your environment is set to a UTF-8 locale (e.g., LC_ALL=en_US.UTF-8) [7][3]. 2. PCRE Library: The -P flag invokes the Perl-Compatible Regular Expression library. Ensure your version of grep supports the -P option [8][5][3]. 3. Range Matching: You can also use this syntax within character classes to match ranges of Unicode characters [3]: grep -P '[\x{3b1}-\x{3bb}]' file.txt This would match any Greek character between alpha (U+03B1) and lambda (U+03BB) [3]. Additional Notes - Braces are optional for simple hexadecimal values (e.g., \x61 is equivalent to 'a'), but \x{...} is the recommended, unambiguous way to handle arbitrary Unicode code points [1][2][3]. - For matching categories of characters (like letters, numbers, or symbols) rather than specific code points, consider using Unicode properties instead, such as \p{L} for any letter or \p{Greek} for Greek characters [9][3][10].

Citations:


Make Check 1 portable and fail closed.

The PowerShell branch uses \x{...} character classes, but Select-String uses .NET regex syntax. Use \u.... escapes there. Also ensure the Windows command exits non-zero when matches are found.

The Bash branch depends on grep -P, which can be unavailable in default macOS environments. Use a portable scanner that supports the required Unicode characters, such as rg.

🧰 Tools
🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 42 - 61, Update the
Windows scanner in the PowerShell section to use .NET-compatible \u.... escapes
and explicitly exit with a non-zero status when Select-String finds matches.
Replace the Bash grep -P pipeline with a portable rg-based scanner that detects
the same Unicode ranges, preserves the existing file and directory exclusions,
and returns success only when no matches are found.


**Failure diagnosis:**
- If output appears, a file contains invisible Unicode characters
- The output shows `filename:line number: offending line`
- Open the file and remove the invisible character(s)
- Common culprits: copy-pasted text from web pages, accidental BOM from editors
- After removal, re-run Check 1 to confirm clean

---

### Check 2: Check Translations (~5s)

Verify all locale translation files are complete and no keys are missing.

**Windows (PowerShell):**
```powershell
node scripts/find-missing-translations.js
```

**Linux/Mac (bash):**
```bash
node scripts/find-missing-translations.js
```

**Pass criteria:** Exit code 0, no "missing" output.

**Failure diagnosis:**
- The script lists missing translation keys per locale
- Add the missing keys to each locale file under `src/i18n/locales/` and `webview-ui/src/i18n/locales/`
- Reference the English (`en`) file as the source of truth
- Use the `roo-translation` skill for translation guidelines
- After adding keys, re-run Check 2 to confirm

---

### Check 3: Lint ESLint (~30s)

Run ESLint with zero-warning tolerance and auto-prune stale suppressions.

**Windows (PowerShell):**
```powershell
cd src; npx eslint --max-warnings=0 --prune-suppressions .
```

**Linux/Mac (bash):**
```bash
cd src && npx eslint --max-warnings=0 --prune-suppressions .
Comment on lines +103 to +108

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '1,270p' .roo/skills/local-ci-precheck/SKILL.md | nl -ba

echo
echo "== package manager files =="
git ls-files | rg '(^|/)(package.json|pnpm-workspace.yaml|pnpm-lock.yaml|package-lock.json|yarn.lock|bun.lockb?)$' || true

echo
echo "== npx occurrences in file =="
rg -n 'npx ' .roo/skills/local-ci-precheck/SKILL.md || true

echo
echo "== check scripts/config references if any =="
rg -n 'no-only-tests|only-run|fail-closed|cache-only|lockfile|lock-file|pnpm exec|npx' .roo/skills/local-ci-precheck/SKILL.md || true

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 218


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpts =="
sed -n '1,270p' .roo/skills/local-ci-precheck/SKILL.md > /tmp/skill_excerpt.txt 2>/dev/null || true
python3 - <<'PY'
from pathlib import Path
p=Path('/tmp/skill_excerpt.txt')
if not p.exists():
    print('MISSING_SKILL_FILE')
    raise SystemExit
lines=p.read_text().splitlines()
for i,l in enumerate(lines, 1):
    print(f'{i:5}: {l}')
PY

echo
echo "== package manager files =="
git ls-files | grep -E '(^|/)(package.json|pnpm-workspace.yaml|pnpm-lock.yaml|package-lock.json|yarn.lock|bun.lockb?)$' || true

echo
echo "== npx occurrences in file =="
grep -n 'npx ' .roo/skills/local-ci-precheck/SKILL.md || true

echo
echo "== package scripts / workspace config references =="
grep -En 'no-only-tests|only-run|fail-closed|cache-only|lockfile|lock-file|pnpm exec|npx|deps-check|vitest|tsc|eslint' .roo/skills/local-ci-precheck/SKILL.md || true

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 13668


Resolve all check commands from pnpm exec.

This skill requires corepack pnpm install, but the repeated eslint, tsc, and vitest commands use bare npx in Windows and Linux/Mac blocks, including re-run examples. Use corepack pnpm/corepack pnpm exec or another fail-closed local-source mechanism so these checks cannot resolve packages from the registry.

Also applies to lines 124, 135-144, 219, 230, 235, and 243.

🧰 Tools
🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 103 - 108, Update all
eslint, tsc, and vitest command examples in the local CI precheck skill,
including rerun examples, to resolve executables through corepack pnpm exec (or
an equivalent fail-closed local dependency mechanism) instead of bare npx.
Preserve the existing Windows and Linux/Mac command structure while ensuring
every check uses the locally installed packages.

Source: Linters/SAST tools

```

**Pass criteria:** Exit code 0, no warnings or errors.

**Failure diagnosis:**

*Scenario A: "There are suppressions left that do not occur anymore"*
- The `eslint-suppressions.json` file has stale entries from rules that were fixed
- The `--prune-suppressions` flag auto-removes them on successful run
- If the prune itself fails, manually open `src/eslint-suppressions.json` and remove entries for rules/files that no longer produce warnings
- After cleanup: `git add src/eslint-suppressions.json` and commit the change

*Scenario B: ESLint rule violations*
- The output shows `filepath:line:col: error [rule-name] message`
- Open each file and fix the code according to the rule
- Run `npx eslint --max-warnings=0 --prune-suppressions .` again after each fix
- Common rules: `@typescript-eslint/no-unused-vars`, `no-console`, `prefer-const`

---

### Check 4: Check Types (~60s)

Run TypeScript type checking across all three project areas.

**Windows (PowerShell):**
```powershell
cd src; npx tsc --noEmit
cd ..\webview-ui; npx tsc --noEmit
cd ..\packages\core; npx tsc --noEmit
```

**Linux/Mac (bash):**
```bash
cd src && npx tsc --noEmit
cd ../webview-ui && npx tsc --noEmit
cd ../packages/core && npx tsc --noEmit
```

**Pass criteria:** Exit code 0 for all three directories, zero type errors.
Comment on lines +133 to +147

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Stop Check 4 after the first failed type check.

The Bash commands run independently without set -e. The PowerShell commands also continue unless they inspect $LASTEXITCODE. This violates the fail-fast rule and can run later checks after an earlier tsc failure.

Run each command in a fail-fast shell block, or check the exit code after every PowerShell command.

🧰 Tools
🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 133 - 147, Update the
Windows and Linux/Mac command blocks in the local CI precheck instructions to
fail fast after the first failed tsc invocation. Use shell fail-fast behavior
for Bash and explicit $LASTEXITCODE checks for PowerShell, ensuring later
directory checks are not run after an earlier type-check failure.


**Failure diagnosis:**
- The output shows `filepath(line,col): error TSxxxx: message`
- `TS2322`: Type mismatch — check the expected vs actual type
- `TS2339`: Property does not exist — check the type definition or add the property
- `TS2345`: Argument type mismatch — cast or adjust the argument
- `TS2531`: Object is possibly null — add null check
- After fixing, re-run the failing directory's `tsc --noEmit` to confirm
- If a new type is introduced, ensure it is exported from the correct module

---

### Check 5: Knip (~30s)

Detect unused code, unused dependencies, and unlisted dependencies.

**Windows (PowerShell):**
```powershell
corepack pnpm knip
```

**Linux/Mac (bash):**
```bash
corepack pnpm knip
```

**Pass criteria:** Exit code 0, no unused exports or unlisted dependencies reported.

**Failure diagnosis:**
- **Unused exports**: Remove the unused function/variable/type, or prefix with `_` if intentionally unused
- **Unused dependencies**: Remove from `package.json` with `corepack pnpm remove <package>`
- **Unlisted dependencies**: Add the missing package to the correct `package.json`
- **Unused files**: Verify the file is truly unused, then delete it
- After fixes, re-run `corepack pnpm knip` to confirm

---

### Check 6: Unit Tests (~120s)

Run all unit and integration tests with coverage.

**Windows (PowerShell):**
```powershell
corepack pnpm turbo run test:coverage
```

**Linux/Mac (bash):**
```bash
corepack pnpm turbo run test:coverage
```

**Alternative (run packages individually):**
```powershell
# Non-core packages
corepack pnpm turbo run test:coverage --filter="!@roo-code/core"

# Core unit tests
corepack pnpm turbo run test:coverage:unit --filter="@roo-code/core"

# Core integration tests
corepack pnpm turbo run test:coverage:integration --filter="@roo-code/core"
```

**Pass criteria:** Exit code 0, all tests pass, no coverage regression below threshold.

**Failure diagnosis:**
- The output shows which test file and test case failed
- **Assertion failure**: Check the expected vs actual value in the test
- **Timeout**: The test may need more time or a mock may be missing
- **Import error**: A module may have been moved or renamed — update the import path
- Fix the failing test or the production code it tests
- Re-run only the failing package first: `cd <package> && npx vitest run` to iterate faster
- Once individual package passes, re-run full suite: `corepack pnpm turbo run test:coverage`

---

### Check 7: Webview Visual (~60s)

Run webview UI snapshot tests to catch visual regressions.

**Windows (PowerShell):**
```powershell
cd webview-ui; npx vitest run
```

**Linux/Mac (bash):**
```bash
cd webview-ui && npx vitest run
```

**Pass criteria:** Exit code 0, all snapshot tests pass.
Comment on lines +224 to +238

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Run the webview visual suite for Check 7.

npx vitest run runs the default Vitest tests. It does not select the visual snapshot script documented by the repository workflow. Check 7 can therefore pass while visual regressions remain undetected.

Use the workspace visual-test command on both platforms:

Suggested replacement
- cd webview-ui; npx vitest run
+ corepack pnpm --filter `@roo-code/vscode-webview` test:visual

The repository’s visual-regression workflow uses pnpm --filter @roo-code/vscode-webview test:visual.

🧰 Tools
🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 224 - 238, Update Check
7 in the local CI precheck instructions to run the visual snapshot suite with
`pnpm --filter `@roo-code/vscode-webview` test:visual` instead of `npx vitest
run`, using the appropriate command syntax for both Windows PowerShell and
Linux/Mac bash while preserving the existing pass criteria.


**Failure diagnosis:**
- **Snapshot mismatch**: If the visual change is intentional, update the snapshot:
```bash
cd webview-ui && npx vitest run --update
```
Then review the diff in `webview-ui/src/__snapshots__/` and commit the updated snapshots
- **Unexpected layout shift**: Check CSS changes in webview-ui components
- **Missing snapshot baseline**: Run with `--update` to create initial snapshots
- If the difference is only font rendering (pixel-level), it may be a platform difference — verify the change looks correct visually

---

## Result Format

After all checks complete, output a summary table:

```
## Local CI Pre-check Results

| # | Check Name | Status | Duration | Error Details |
|---|--------------------|--------|----------|---------------|
| 1 | Invisible Chars | ✅ PASS | 1.2s | — |
| 2 | Check Translations | ✅ PASS | 3.1s | — |
| 3 | Lint ESLint | ✅ PASS | 22.4s | — |
| 4 | Check Types | ❌ FAIL | 45.2s | TS2322 in src/utils.ts:42 |
| 5 | Knip | ⏭️ SKIP | — | Skipped due to Check 4 failure |
| 6 | Unit Tests | ⏭️ SKIP | — | Skipped due to Check 4 failure |
| 7 | Webview Visual | ⏭️ SKIP | — | Skipped due to Check 4 failure |

**Result: FAILED** — Fix Check 4 (Check Types) before pushing.
Comment on lines +256 to +269

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language to the result-format code fence.

Markdownlint reports MD040 for the untyped fence at Line 256. Use markdown, text, or another appropriate language identifier.

-```
+```markdown
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 256-256: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 256 - 269, Update the
result-format code fence in the “Local CI Pre-check Results” section to include
an appropriate language identifier, such as markdown or text, while preserving
the existing table content.

Source: Linters/SAST tools

```

**Rules:**
- If all 7 checks PASS → output `✅ All checks passed. Safe to push.`
- If any check FAILS → stop immediately, skip remaining checks, output the failure table
- Include the exact error message (first 3 lines) in the Error Details column
- Include the suggested fix below the table

---

## Skip Conditions

Skip the entire pre-check if ANY of the following is true:

1. **Flag**: User passed `--skip-ci-check` in the push command
2. **Non-source only**: `git diff --name-only HEAD` shows only files matching:
- `*.md`
- `*.json` (excluding `package.json` and `tsconfig.json`)
- `*.yml` / `*.yaml` (excluding workflow logic changes)
- `.github/` label/config changes
- `docs/` directory changes
- `.gitignore`, `.gitattributes`

When skipping, output: `⏭️ CI pre-check skipped (no source code changes or --skip-ci-check flag).`
Comment on lines +280 to +293

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Base skip decisions on the commits being pushed.

git diff --name-only HEAD compares the worktree and index with the current HEAD. It does not include commits already on the branch that will be pushed. The skill can therefore skip checks for committed source changes.

The rule “excluding workflow logic changes” also cannot be evaluated from file names alone. Inspect the pushed diff and use the local/remote refs provided by the pre-push context before applying the whitelist.

🧰 Tools
🪛 SkillSpector (2.5.1)

[warning] 103: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 108: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 124: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 135: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 136: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 137: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 142: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 143: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 144: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 219: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 230: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 235: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))


[warning] 243: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Remediation: Pin the version: npx @scope/server@1.2.3

(MCP Rug Pull (RP1))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.roo/skills/local-ci-precheck/SKILL.md around lines 280 - 293, Update the
skip-condition logic to inspect the complete pushed commit range using the local
and remote refs available in the pre-push context, rather than `git diff
--name-only HEAD`. Determine whether source changes exist in the pushed diff,
and evaluate workflow files by their actual diff content instead of filename
alone before applying the non-source whitelist.


---

## Windows Environment Notes

1. **Use `corepack pnpm`** instead of bare `pnpm` to avoid PowerShell execution policy errors (`pnpm.ps1 cannot be loaded`)
2. **Use `Select-String`** instead of `grep` for pattern matching in PowerShell
3. **Use `;`** as command separator in PowerShell (not `&&`)
4. **Use `cd dir; command`** pattern — PowerShell `cd` does not chain with `&&` like bash
5. **Path separators**: Use `\` in PowerShell commands, `/` in bash commands
6. **Exit code checking**: PowerShell does not propagate exit codes the same way as bash — check `$LASTEXITCODE` after external commands if needed
32 changes: 32 additions & 0 deletions apps/vscode-e2e/fixtures/terminal-lifecycle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"fixtures": [
{
"match": {
"userMessage": "TERMINAL_LIFECYCLE_E2E"
},
"response": {
"toolCalls": [
{
"name": "execute_command",
"arguments": "{\"command\":\"echo lifecycle-first\"}",
"id": "call_terminal_lifecycle_001"
Comment on lines +4 to +12

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Constrain both prompt fixtures to the first turn.

These fixtures seed flows that continue after a tool result, but neither match includes sequenceIndex: 0. The original user prompt can remain in later request history. The fixture can then re-issue the first command and prevent the programmatic follow-up from advancing.

Proposed fix
 			"match": {
+				"sequenceIndex": 0,
 				"userMessage": "TERMINAL_LIFECYCLE_E2E"
 			},
...
 			"match": {
+				"sequenceIndex": 0,
 				"userMessage": "TERMINAL_LIFECYCLE_CANCEL_E2E"
 			},

As per coding guidelines, multi-turn fixtures must match turn 1 with sequenceIndex: 0 and match turn 2 using toolCallId.

Also applies to: 18-26

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode-e2e/fixtures/terminal-lifecycle.json` around lines 4 - 12, Update
both prompt fixture match blocks in the terminal lifecycle flow to include
sequenceIndex: 0, ensuring they only match the first turn. Preserve the existing
tool response behavior and use the appropriate toolCallId match for the
subsequent turn so the programmatic follow-up cannot advance the fixture.

Source: Coding guidelines

}
]
}
},
{
"match": {
"userMessage": "TERMINAL_LIFECYCLE_CANCEL_E2E"
},
"response": {
"toolCalls": [
{
"name": "execute_command",
"arguments": "{\"command\":\"sleep 30\"}",
"id": "call_terminal_lifecycle_cancel_001"
}
]
}
}
]
}
Loading
Loading