Repository navigation
integration(HOLMES): MP‑01..03 + score breakdown + CI detect + precommit #334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dc6a6a9
51ebfcb
f9545bd
3e6f1ca
79cc863
6b6cf1f
d0858b2
fd5a861
59d2e86
cec48de
ed31a11
a65124d
3d36925
bfb9f5d
0f39f02
871d096
d99dda0
64fbca8
ff32c0d
084f2b1
1a31216
4ee4134
c995e7a
794e205
0cb3c34
3c995bb
c089837
50b0db0
5a34be0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,154 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Auto-sync pnpm-lock.yaml when dependency resolution manifests change. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Triggers only when staged changes affect fields that impact resolution: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # dependencies/devDependencies/optionalDependencies/peerDependencies, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # overrides (npm or pnpm.overrides), pnpm.peerDependencyRules, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # pnpm.packageExtensions, workspaces, or pnpm-workspace.yaml. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Also triggers when the root package.json `packageManager` field changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (e.g., pnpm version bump or switching package managers). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Runs `pnpm install --lockfile-only` and stages pnpm-lock.yaml. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Blocks commit only if pnpm is missing or wrong version AND an update is required. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Skip entirely with: WESLEY_SKIP_LOCKFILE_HOOK=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "${WESLEY_SKIP_LOCKFILE_HOOK:-0}" == "1" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "⚠️ Skipping lockfile guard (WESLEY_SKIP_LOCKFILE_HOOK=1)." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Only act if package manifests are staged | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! echo "$STAGED_FILES" | grep -E -q '(^|/)package.json$|(^|/)pnpm-workspace.yaml$'; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "🔎 Checking if staged manifest changes affect the lockfile..." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NEEDS_UPDATE=0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # If pnpm-workspace.yaml changed, lockfile may need update (importers layout) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if echo "$STAGED_FILES" | grep -Eq '(^|/)pnpm-workspace.yaml$'; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NEEDS_UPDATE=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Node.js may be missing; you call it unguarded. If only package.json is staged and Node isn’t installed, the hook dies mid-flight. Fail early with a clear message (but don’t require Node for pure workspace changes). echo "🔎 Checking if staged manifest changes affect the lockfile..."
NEEDS_UPDATE=0
+# If any package.json is staged, ensure Node is available for JSON diffs
+if echo "$STAGED_FILES" | grep -Eq '(^|/)package.json$'; then
+ if ! command -v node >/dev/null 2>&1; then
+ echo "❌ Node.js not found; required to analyze staged package.json diffs." >&2
+ echo " Install Node.js (or set WESLEY_SKIP_LOCKFILE_HOOK=1 to skip this guard)." >&2
+ exit 1
+ fi
+fi
+
# If pnpm-workspace.yaml changed, lockfile may need update (importers layout)
if echo "$STAGED_FILES" | grep -Eq '(^|/)pnpm-workspace.yaml$'; then
NEEDS_UPDATE=1
fiAlso applies to: 83-93 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Helper: determine if a package.json change affects resolution using Node (no jq dependency) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| check_pkg_change() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local path="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Read staged version of the file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local staged_json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! staged_json=$(git show ":$path" 2>/dev/null); then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Deleted or unreadable in index -> treat as affecting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Read HEAD version of the file (may not exist) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local head_json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| head_json=$(git show "HEAD:$path" 2>/dev/null || echo '{}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Use node to compare only resolution-impacting fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| node -e ' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function pick(x){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!x||typeof x!="object") return {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dependencies:x.dependencies||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| devDependencies:x.devDependencies||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| optionalDependencies:x.optionalDependencies||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| peerDependencies:x.peerDependencies||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| overrides:x.overrides||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pnpmOverrides:(x.pnpm&&x.pnpm.overrides)||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pnpmPeerRules:(x.pnpm&&x.pnpm.peerDependencyRules)||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pnpmPackageExtensions:(x.pnpm&&x.pnpm.packageExtensions)||{}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workspaces:x.workspaces||null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // stable stringify with sorted keys | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function sort(obj){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(Array.isArray(obj)) return obj.map(sort); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(obj&&typeof obj==="object"){ return Object.keys(obj).sort().reduce((a,k)=>{a[k]=sort(obj[k]);return a;},{}); } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return obj; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return JSON.stringify(sort(out)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+61
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Optional: treat workspaces array as an unordered set. Re-ordering - function sort(obj){
- if(Array.isArray(obj)) return obj.map(sort);
+ function sort(obj){
+ if(Array.isArray(obj)) {
+ // Sort arrays of strings for stability; deep-sort objects within arrays otherwise.
+ if (obj.every(v => typeof v === "string")) return [...obj].sort();
+ return obj.map(sort);
+ }
if(obj&&typeof obj==="object"){ return Object.keys(obj).sort().reduce((a,k)=>{a[k]=sort(obj[k]);return a;},{}); }
return obj;
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fs=require("node:fs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const staged=JSON.parse(fs.readFileSync(0,"utf8")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const head=JSON.parse(process.argv[1]||"{}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const s=pick(staged), h=pick(head); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(s===h? 10: 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ' "${head_json}" <<<"${staged_json}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+47
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Feeding full JSON via argv risks ARG_MAX limits; use file descriptors. Large manifests can exceed shell arg limits. Pass HEAD via FD and staged via STDIN. - node -e '
+ node - <<'NODE'
function pick(x){
if(!x||typeof x!="object") return {};
const out={
dependencies:x.dependencies||{},
devDependencies:x.devDependencies||{},
optionalDependencies:x.optionalDependencies||{},
peerDependencies:x.peerDependencies||{},
overrides:x.overrides||{},
pnpmOverrides:(x.pnpm&&x.pnpm.overrides)||{},
pnpmPeerRules:(x.pnpm&&x.pnpm.peerDependencyRules)||{},
pnpmPackageExtensions:(x.pnpm&&x.pnpm.packageExtensions)||{},
workspaces:x.workspaces||null
};
// stable stringify with sorted keys
function sort(obj){
- if(Array.isArray(obj)) return obj.map(sort);
+ if(Array.isArray(obj)) return obj.map(sort);
if(obj&&typeof obj==="object"){ return Object.keys(obj).sort().reduce((a,k)=>{a[k]=sort(obj[k]);return a;},{}); }
return obj;
}
return JSON.stringify(sort(out));
}
- const fs=require("node:fs");
- const staged=JSON.parse(fs.readFileSync(0,"utf8"));
- const head=JSON.parse(process.argv[1]||"{}");
+ const fs=require("node:fs");
+ const staged=JSON.parse(fs.readFileSync(0,"utf8"));
+ const head=JSON.parse(fs.readFileSync(3,"utf8"));
const s=pick(staged), h=pick(head);
process.exit(s===h? 10: 0);
- ' "${head_json}" <<<"${staged_json}"
+NODE
+ 3<<<"${head_json}" <<<"${staged_json}"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case $? in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0) return 0 ;; # changed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10) return 1 ;; # no change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *) return 0 ;; # on parser error, be safe and assume change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Evaluate all staged package.json files | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while IFS= read -r f; do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [[ -z "$f" ]] && continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$f" =~ (^|/)package.json$ ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if check_pkg_change "$f"; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NEEDS_UPDATE=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done < <(echo "$STAGED_FILES") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Additionally, if root package.json's packageManager changed, require action | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if echo "$STAGED_FILES" | grep -qx "package.json"; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ROOT_STAGED=$(git show ":package.json" 2>/dev/null || echo '{}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ROOT_HEAD=$(git show "HEAD:package.json" 2>/dev/null || echo '{}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PM_CHANGE_OUTPUT=$(node -e ' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fs=require("node:fs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const staged=JSON.parse(fs.readFileSync(0,"utf8")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const head=JSON.parse(process.argv[1]||"{}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const s=staged.packageManager||""; const h=head.packageManager||""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(s!==h){ console.log(`${h}=>${s}`); process.exit(0);} else process.exit(10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }catch{ process.exit(0) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ' "${ROOT_HEAD}" <<<"${ROOT_STAGED}" || true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PM_CHANGED=$? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$PM_CHANGED" -eq 0 ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PM_NEW="${PM_CHANGE_OUTPUT#*=>}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PM_OLD="${PM_CHANGE_OUTPUT%=>*}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # If switching away from pnpm, block with guidance (this repo standardizes on pnpm) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ ! "$PM_NEW" =~ ^pnpm@ ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ packageManager changed from '${PM_OLD:-<none>}' to '${PM_NEW:-<none>}', which is not pnpm." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo " This repository is configured for pnpm; update CI/workflows and lockfiles in a dedicated PR if switching managers." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo " To proceed with pnpm, set packageManager to 'pnpm@<version>' and re-run the commit." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Switching pnpm version: ensure lockfile is regenerated | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NEEDS_UPDATE=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+98
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. packageManager change detection is broken (always triggers). You throw away Node’s exit code with command substitution and Apply this minimal, correct logic keyed on output presence: - PM_CHANGE_OUTPUT=$(node -e '
+ PM_CHANGE_OUTPUT=$(node -e '
try{
const fs=require("node:fs");
const staged=JSON.parse(fs.readFileSync(0,"utf8"));
const head=JSON.parse(process.argv[1]||"{}");
const s=staged.packageManager||""; const h=head.packageManager||"";
if(s!==h){ console.log(`${h}=>${s}`); process.exit(0);} else process.exit(10);
}catch{ process.exit(0) }
- ' "${ROOT_HEAD}" <<<"${ROOT_STAGED}" || true)
- PM_CHANGED=$?
- if [[ "$PM_CHANGED" -eq 0 ]]; then
+ ' "${ROOT_HEAD}" <<<"${ROOT_STAGED}" 2>/dev/null || true)
+ if [[ -n "$PM_CHANGE_OUTPUT" ]]; then
PM_NEW="${PM_CHANGE_OUTPUT#*=>}"
PM_OLD="${PM_CHANGE_OUTPUT%=>*}"
# If switching away from pnpm, block with guidance (this repo standardizes on pnpm)
if [[ ! "$PM_NEW" =~ ^pnpm@ ]]; then
echo "❌ packageManager changed from '${PM_OLD:-<none>}' to '${PM_NEW:-<none>}', which is not pnpm." >&2
echo " This repository is configured for pnpm; update CI/workflows and lockfiles in a dedicated PR if switching managers." >&2
echo " To proceed with pnpm, set packageManager to 'pnpm@<version>' and re-run the commit." >&2
exit 1
fi
# Switching pnpm version: ensure lockfile is regenerated
NEEDS_UPDATE=1
fi🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$NEEDS_UPDATE" != "1" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Manifest changes do not impact lockfile; skipping pnpm install" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "🧩 Manifest changes affect dependency resolution. Updating pnpm-lock.yaml..." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Ensure pnpm exists and version matches only when we need to update | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! command -v pnpm >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ pnpm not found on PATH." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo " Tip: corepack enable && corepack prepare pnpm@<version> --activate" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REQ=$(node -e "try{const pm=require('./package.json').packageManager||'';if(pm.startsWith('pnpm@')){console.log(pm.split('@')[1])}}catch{process.exit(0)}" || true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HAVE=$(pnpm --version || true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ -n "${REQ:-}" && "${HAVE:-}" != "$REQ" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ pnpm version mismatch: required $REQ (from packageManager), found $HAVE." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo " Run: corepack prepare pnpm@$REQ --activate" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+137
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major pnpm version check reads working tree, not staged manifest. You may enforce the wrong version if the staged -REQ=$(node -e "try{const pm=require('./package.json').packageManager||'';if(pm.startsWith('pnpm@')){console.log(pm.split('@')[1])}}catch{process.exit(0)}" || true)
+REQ=$(node -e '
+ const fs=require("node:fs");
+ let data="{}";
+ try{ data=fs.readFileSync(0,"utf8"); }catch{}
+ try{
+ const pm=(JSON.parse(data).packageManager||"");
+ if(pm.startsWith("pnpm@")) console.log(pm.split("@")[1]);
+ }catch{}
+' <<<"$(git show ':package.json' 2>/dev/null || cat package.json 2>/dev/null || echo '{}')" || true)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pnpm install --lockfile-only | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! git diff --quiet -- pnpm-lock.yaml; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git add pnpm-lock.yaml | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Updated and staged pnpm-lock.yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ pnpm-lock.yaml already up to date" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+147
to
+152
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Untracked pnpm-lock.yaml won’t be staged (git diff ignores untracked). If the lockfile is newly created, your check stays quiet and you skip Use porcelain status to detect both modified and untracked: -if ! git diff --quiet -- pnpm-lock.yaml; then
- git add pnpm-lock.yaml
- echo "✅ Updated and staged pnpm-lock.yaml"
-else
- echo "✅ pnpm-lock.yaml already up to date"
-fi
+if test -n "$(git status --porcelain=v1 -- pnpm-lock.yaml)"; then
+ git add pnpm-lock.yaml
+ echo "✅ Updated and staged pnpm-lock.yaml"
+else
+ echo "✅ pnpm-lock.yaml already up to date"
+fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,11 +5,10 @@ name: Wesley CLI Quick Check | |||||||||||||||||||
|
|
||||||||||||||||||||
| on: | ||||||||||||||||||||
| push: | ||||||||||||||||||||
| paths: | ||||||||||||||||||||
| - 'packages/wesley-cli/**' | ||||||||||||||||||||
| branches: | ||||||||||||||||||||
| - main | ||||||||||||||||||||
| pull_request: | ||||||||||||||||||||
| paths: | ||||||||||||||||||||
| - 'packages/wesley-cli/**' | ||||||||||||||||||||
| types: [opened, synchronize, reopened] | ||||||||||||||||||||
|
|
||||||||||||||||||||
| env: | ||||||||||||||||||||
| FORCE_COLOR: 1 | ||||||||||||||||||||
|
|
@@ -25,33 +24,52 @@ jobs: | |||||||||||||||||||
| with: | ||||||||||||||||||||
| submodules: recursive # For Bats plugins | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Detect CLI changes | ||||||||||||||||||||
| id: changes | ||||||||||||||||||||
| uses: dorny/paths-filter@v3 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| filters: | | ||||||||||||||||||||
| cli: | ||||||||||||||||||||
| - 'packages/wesley-cli/**' | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Skip check (no CLI changes) | ||||||||||||||||||||
| if: steps.changes.outputs.cli != 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| echo "No changes under packages/wesley-cli; skipping quick CLI tests." | ||||||||||||||||||||
| echo "::notice title=Quick Check Skipped::No CLI changes detected" | ||||||||||||||||||||
|
Comment on lines
+27
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Change detection is correct but notification could be clearer. Using dorny/paths-filter to skip CLI tests when no CLI changes exist is smart and saves CI time. The skip notification on lines 38-39 is visible. BUT: The workflow still shows as "success" even when everything was skipped. Users might not notice the notice. Consider:
Current approach is acceptable but could be more obvious. 🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Setup pnpm | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| uses: pnpm/action-setup@v4 | ||||||||||||||||||||
| - name: Verify pnpm version | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| echo "pnpm: $(pnpm --version)" | ||||||||||||||||||||
| node -v | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Comment on lines
44
to
48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why verify pnpm version when skipping all CLI tests? Lines 42-43 conditionally setup pnpm only if CLI changes exist. But lines 44-48 ALWAYS verify pnpm version, even when steps.changes.outputs.cli != 'true'. This means:
Either add the conditional guard to this step too, or remove it entirely (setup-pnpm already validates the version). Apply this diff: - name: Verify pnpm version
+ if: steps.changes.outputs.cli == 'true'
run: |📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| - name: Setup Node.js (LTS) | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| uses: actions/setup-node@v4 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| node-version: '20' | ||||||||||||||||||||
| cache: 'pnpm' | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Install Bats | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| curl -LO https://github.com/bats-core/bats-core/archive/v1.12.0.tar.gz | ||||||||||||||||||||
| tar -xzf v1.12.0.tar.gz | ||||||||||||||||||||
| sudo ./bats-core-1.12.0/install.sh /usr/local | ||||||||||||||||||||
| echo "/usr/local/bin" >> $GITHUB_PATH | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Install dependencies | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| pnpm install --frozen-lockfile | ||||||||||||||||||||
| - name: Verify lockfile unchanged | ||||||||||||||||||||
| run: git diff --exit-code -- pnpm-lock.yaml | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Comment on lines
68
to
70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lockfile check runs unconditionally but dependencies were conditionally installed. Line 65-67 installs dependencies ONLY when CLI changes exist. But line 68-70 verifies lockfile ALWAYS. If no CLI changes → no pnpm install → git diff checks nothing meaningful. This step will pass vacuously, giving false confidence. Move lockfile verification inside the conditional block OR make dependency installation unconditional (if you want to enforce lockfile hygiene on every push). Apply this diff: - name: Verify lockfile unchanged
+ if: steps.changes.outputs.cli == 'true'
run: git diff --exit-code -- pnpm-lock.yaml📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| - name: Initialize git for CLI tests | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| cd packages/wesley-cli | ||||||||||||||||||||
| git init . | ||||||||||||||||||||
|
|
@@ -61,12 +79,14 @@ jobs: | |||||||||||||||||||
| git commit -m "CI test commit" || echo "Nothing to commit" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Run CLI tests | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| cd packages/wesley-cli | ||||||||||||||||||||
| echo "🧪 Running Wesley CLI Tests..." | ||||||||||||||||||||
| pnpm test | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Smoke test CLI functionality | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| cd packages/wesley-cli | ||||||||||||||||||||
| echo "" | ||||||||||||||||||||
|
|
@@ -81,6 +101,7 @@ jobs: | |||||||||||||||||||
| echo 'type Query { hello: String }' | node ../wesley-host-node/bin/wesley.mjs generate --schema - --json --quiet || echo "✓ Expected parser failure" || true | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Success notification | ||||||||||||||||||||
| if: steps.changes.outputs.cli == 'true' | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| echo "✅ Wesley CLI quick check passed!" | ||||||||||||||||||||
| echo "All 12 end-to-end tests successful" | ||||||||||||||||||||
|
|
||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Filename robustness: prefer NUL-delimited plumbing.
Newlines in paths are rare but possible. Use
-zand mapfile.Also applies to: 83-93
🤖 Prompt for AI Agents