Skip to content

Add pr-visual-writeup skill to .agents/skills - #1354

Merged
BilalG1 merged 2 commits into
devfrom
add-pr-visual-writeup-skill
Apr 20, 2026
Merged

BilalG1 merged 2 commits into
devfrom
add-pr-visual-writeup-skill

Conversation

@BilalG1

@BilalG1 BilalG1 commented Apr 20, 2026 •

Copy link
Copy Markdown
Collaborator

Shared agent skill under the cross-client .agents/skills/ convention so Claude Code, Codex, and other compliant agents can discover it.

Summary by CodeRabbit

  • New Features

    • Added an end-to-end workflow skill for automating visual-rich PR descriptions with screenshot capture, asset processing, and upload capabilities.
  • Documentation

    • Added reference guides covering screenshot capture patterns, asset upload workflows, and structured PR body templates.
  • Chores

    • Added helper scripts for development server detection, media conversion, and GitHub gist uploads.

BilalG1 added 2 commits April 20, 2026 10:49
Shared agent skill under the cross-client `.agents/skills/` convention
so Claude Code, Codex, and other compliant agents can discover it.
Claude Code only scans .claude/skills/ (not the cross-client
.agents/skills/ convention), so point it at the shared directory
via a symlink. Any skill added under .agents/skills/ is picked up
by Claude Code, Codex, and other compliant agents.
@vercel

vercel Bot commented Apr 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-auth-hosted-components Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-backend Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-dashboard Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-demo Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-docs Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-preview-backend Ready Ready Preview, Comment Apr 20, 2026 5:59pm
stack-preview-dashboard Ready Ready Preview, Comment Apr 20, 2026 5:59pm

@coderabbitai

coderabbitai Bot commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Introduces a new PR visual writeup skill comprising documentation, workflow patterns, and helper scripts for capturing UI screenshots across theme and viewport variations, converting scroll animations to GIFs, uploading assets to GitHub gists, and composing structured PR bodies with embedded visuals.

Changes

Cohort / File(s) Summary
Skill Documentation
.agents/skills/pr-visual-writeup/SKILL.md, .agents/skills/pr-visual-writeup/references/capture-patterns.md, .agents/skills/pr-visual-writeup/references/gist-upload.md, .agents/skills/pr-visual-writeup/references/pr-body-template.md
Comprehensive documentation defining the end-to-end visual writeup workflow: screenshot capture patterns across theme/viewport matrices, gist-based asset upload mechanics, PR body templating conventions, and anti-patterns to avoid.
Helper Scripts
.agents/skills/pr-visual-writeup/scripts/convert_clips.sh, .agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh, .agents/skills/pr-visual-writeup/scripts/upload_gist.sh
Three utility scripts: parallel webm-to-gif conversion via ffmpeg, local Node.js dev server detection by port scanning, and gist creation/upload via GitHub CLI with PAT-based authentication.
Configuration
.claude/skills
Simple reference pointer to the agents skills directory.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • N2D4

Poem

🐰 Hop along with screenshots bright,
Gifs a-dancing in the night,
Gists that gleam with visual cheer,
PR reviews crystal clear! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add pr-visual-writeup skill to .agents/skills' clearly and concisely describes the main change: introducing a new agent skill to a shared skills directory.
Description check ✅ Passed The description briefly explains the purpose (shared agent skill for cross-client discovery) and references guidelines, meeting basic requirements despite the template being minimal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-pr-visual-writeup-skill

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

🧹 Nitpick comments (2)
.agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh (1)

26-29: Exit code is ambiguous when no servers are found.

The stderr message says "no listening node servers" but the script still exits 0, so callers (or the SKILL.md workflow that uses this to pick a port) can't distinguish "nothing running" from "one found". Consider exit 1 so scripted consumers can branch on it.

Proposed change
 if [ -z "$ports" ]; then
   echo "no listening node servers in $MIN-$MAX" >&2
-  exit 0
+  exit 1
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh around lines
26 - 29, The script currently prints "no listening node servers in $MIN-$MAX" to
stderr but returns exit code 0, which is ambiguous for callers; change the exit
behavior so that when the variable "ports" is empty (the if [ -z "$ports" ]
branch) the script exits with a non-zero status (e.g., exit 1) so consumers can
detect "no servers found"; update the echo/exit in that branch accordingly and
ensure any tests or callers expecting success are adjusted to treat the non-zero
exit as "no servers".
.agents/skills/pr-visual-writeup/scripts/upload_gist.sh (1)

69-73: $OLDPWD is fragile as the gist-id.txt destination.

$OLDPWD is whatever directory the caller was in before this script ran, which may not be where they expect the id file (e.g. if they invoked via an absolute path from a different cwd, or if the calling script itself cd'd). SKILL.md says "Stashes the gist id in ./gist-id.txt", so writing to $PWD captured before the internal cd "$WORK/gist" would be more predictable.

Proposed fix
+ORIG_PWD=$PWD
@@
 cd "$WORK/gist"
@@
-echo "$GIST_ID" > "$OLDPWD/gist-id.txt"
+echo "$GIST_ID" > "$ORIG_PWD/gist-id.txt"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/pr-visual-writeup/scripts/upload_gist.sh around lines 69 -
73, The script currently writes the GIST_ID to "$OLDPWD/gist-id.txt", which is
fragile; capture the current working directory into a stable variable (e.g.
ORIGINAL_PWD="${PWD}") before the internal cd "$WORK/gist" and then write the id
to "$ORIGINAL_PWD/gist-id.txt" instead of "$OLDPWD"; update the echo that
outputs the raw URLs if it should reference the same directory variable or leave
it relative to the script's working directory, but replace any use of "$OLDPWD"
with the saved ORIGINAL_PWD variable and ensure GIST_ID is written to
./gist-id.txt as promised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/pr-visual-writeup/references/gist-upload.md:
- Around line 48-50: The fenced code block containing the URL template should
include a language tag to satisfy markdownlint MD040; update the block that
currently contains
"https://gist.githubusercontent.com/<user>/<gist-id>/raw/<filename>" so the
opening fence is ```text (i.e., add the "text" language identifier) to the
existing fenced code block.

In @.agents/skills/pr-visual-writeup/scripts/upload_gist.sh:
- Around line 42-56: The script currently copies files into "$WORK/gist/" and
lets later cp overwrite files with the same basename; update the loop that
iterates over input dirs (the for d in "$@"; do / for f in "$d"/*; do block) to
detect basename collisions before copying: compute b=$(basename "$f"), check a
tracking map (e.g. an associative array or temporary file keyed by "$b") to see
if b was already seen, and if so print a clear error or warning to stderr
(including both source paths) and exit non‑zero (or continue if you choose to
only warn); otherwise record the basename -> source and proceed to copy and
increment count; ensure messages use >&2 and preserve the existing staged count
behavior.
- Around line 64-66: The current git invocation in upload_gist.sh embeds the PAT
in the command argv via -c credential.helper="!f() { echo username=$USER; echo
password=$TOKEN; }; f", exposing the token to other same-UID processes; change
the flow to avoid passing $TOKEN on the command line by using GIT_ASKPASS (or an
askpass helper read from stdin) instead of the inline credential.helper: create
a small askpass helper that prints the password to stdout when invoked and set
GIT_ASKPASS to its path (or export a process-safe askpass via a here-doc) before
invoking git push, and remove the inline -c credential.helper snippet so the
token is never present in the git argv.

In @.agents/skills/pr-visual-writeup/SKILL.md:
- Around line 129-137: Markdownlint flagged MD040 for the directory tree fenced
code block in .agents/skills/pr-visual-writeup/SKILL.md (the block starting with
"/tmp/pr-<N>-visuals/"); fix it by adding a language identifier to the opening
fence (e.g., change the opening "```" to "```text") so the block becomes a
labeled code block, ensure the closing fence remains present, and apply the same
fix to any other unlabeled fenced blocks in that file.

---

Nitpick comments:
In @.agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh:
- Around line 26-29: The script currently prints "no listening node servers in
$MIN-$MAX" to stderr but returns exit code 0, which is ambiguous for callers;
change the exit behavior so that when the variable "ports" is empty (the if [ -z
"$ports" ] branch) the script exits with a non-zero status (e.g., exit 1) so
consumers can detect "no servers found"; update the echo/exit in that branch
accordingly and ensure any tests or callers expecting success are adjusted to
treat the non-zero exit as "no servers".

In @.agents/skills/pr-visual-writeup/scripts/upload_gist.sh:
- Around line 69-73: The script currently writes the GIST_ID to
"$OLDPWD/gist-id.txt", which is fragile; capture the current working directory
into a stable variable (e.g. ORIGINAL_PWD="${PWD}") before the internal cd
"$WORK/gist" and then write the id to "$ORIGINAL_PWD/gist-id.txt" instead of
"$OLDPWD"; update the echo that outputs the raw URLs if it should reference the
same directory variable or leave it relative to the script's working directory,
but replace any use of "$OLDPWD" with the saved ORIGINAL_PWD variable and ensure
GIST_ID is written to ./gist-id.txt as promised.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7950e21-8b05-4aaa-bf34-f1ee4a2725fc

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc1836 and cf60902.

📒 Files selected for processing (8)
  • .agents/skills/pr-visual-writeup/SKILL.md
  • .agents/skills/pr-visual-writeup/references/capture-patterns.md
  • .agents/skills/pr-visual-writeup/references/gist-upload.md
  • .agents/skills/pr-visual-writeup/references/pr-body-template.md
  • .agents/skills/pr-visual-writeup/scripts/convert_clips.sh
  • .agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh
  • .agents/skills/pr-visual-writeup/scripts/upload_gist.sh
  • .claude/skills

Comment thread .agents/skills/pr-visual-writeup/references/gist-upload.md
Comment on lines +42 to +56
# 3. Stage every file from every input dir. Don't recurse — gists are flat.
count=0
for d in "$@"; do
for f in "$d"/*; do
[ -f "$f" ] || continue
cp "$f" "$WORK/gist/"
count=$((count+1))
done
done

if [ $count -eq 0 ]; then
echo "no files found in input directories" >&2
exit 1
fi
echo "staged $count files" >&2

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.

⚠️ Potential issue | 🟡 Minor

Silent filename collisions across input dirs.

With upload_gist.sh "desc" shots/ clips/, if any basename appears in both dirs the second cp overwrites the first and the collision is invisible in the uploaded gist. gist-upload.md already documents "a later cp wins", but since the whole point of the script is a reproducible asset push, at minimum warn (or fail) on collision rather than silently dropping a screenshot.

Proposed fix
 for d in "$@"; do
   for f in "$d"/*; do
     [ -f "$f" ] || continue
+    base=$(basename "$f")
+    if [ -e "$WORK/gist/$base" ]; then
+      echo "collision: $base already staged (from a prior dir); refusing to overwrite" >&2
+      exit 1
+    fi
     cp "$f" "$WORK/gist/"
     count=$((count+1))
   done
 done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/pr-visual-writeup/scripts/upload_gist.sh around lines 42 -
56, The script currently copies files into "$WORK/gist/" and lets later cp
overwrite files with the same basename; update the loop that iterates over input
dirs (the for d in "$@"; do / for f in "$d"/*; do block) to detect basename
collisions before copying: compute b=$(basename "$f"), check a tracking map
(e.g. an associative array or temporary file keyed by "$b") to see if b was
already seen, and if so print a clear error or warning to stderr (including both
source paths) and exit non‑zero (or continue if you choose to only warn);
otherwise record the basename -> source and proceed to copy and increment count;
ensure messages use >&2 and preserve the existing staged count behavior.

Comment on lines +64 to +66
git -c credential.helper= \
-c credential.helper="!f() { echo username=$USER; echo password=$TOKEN; }; f" \
push --quiet

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.

⚠️ Potential issue | 🟡 Minor

PAT is briefly visible to other processes on the box.

Passing the token via -c credential.helper="!f() { echo username=$USER; echo password=$TOKEN; }; f" embeds it in the git argv, so any same-UID process that reads /proc/<pid>/cmdline during the push can see it. GIT_ASKPASS (or piping the helper via stdin) avoids putting the secret on the command line. Low risk on a dev workstation; worth noting for CI contexts.

Alternative using GIT_ASKPASS
-git -c credential.helper= \
-    -c credential.helper="!f() { echo username=$USER; echo password=$TOKEN; }; f" \
-    push --quiet
+ASKPASS=$(mktemp)
+trap 'rm -f "$ASKPASS"' RETURN
+cat > "$ASKPASS" <<EOF
+#!/usr/bin/env bash
+case "\$1" in
+  Username*) echo "$USER" ;;
+  Password*) echo "$TOKEN" ;;
+esac
+EOF
+chmod +x "$ASKPASS"
+GIT_ASKPASS="$ASKPASS" GIT_TERMINAL_PROMPT=0 git -c credential.helper= push --quiet
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
git -c credential.helper= \
-c credential.helper="!f() { echo username=$USER; echo password=$TOKEN; }; f" \
push --quiet
ASKPASS=$(mktemp)
trap 'rm -f "$ASKPASS"' RETURN
cat > "$ASKPASS" <<EOF
#!/usr/bin/env bash
case "\$1" in
Username*) echo "$USER" ;;
Password*) echo "$TOKEN" ;;
esac
EOF
chmod +x "$ASKPASS"
GIT_ASKPASS="$ASKPASS" GIT_TERMINAL_PROMPT=0 git -c credential.helper= push --quiet
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/pr-visual-writeup/scripts/upload_gist.sh around lines 64 -
66, The current git invocation in upload_gist.sh embeds the PAT in the command
argv via -c credential.helper="!f() { echo username=$USER; echo password=$TOKEN;
}; f", exposing the token to other same-UID processes; change the flow to avoid
passing $TOKEN on the command line by using GIT_ASKPASS (or an askpass helper
read from stdin) instead of the inline credential.helper: create a small askpass
helper that prints the password to stdout when invoked and set GIT_ASKPASS to
its path (or export a process-safe askpass via a here-doc) before invoking git
push, and remove the inline -c credential.helper snippet so the token is never
present in the git argv.

Comment on lines +129 to +137
```
/tmp/pr-<N>-visuals/
├── scope.md # phase 1 output
├── shots/ # captured PNGs
├── clips/ # webm + gif scroll animations
├── body.md # composed PR description
├── gist-id.txt # for re-pushing if you add more shots later
└── urls.txt # raw URL per file, for copy-paste
```

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.

⚠️ Potential issue | 🟡 Minor

MD040: add a language to the tree diagram fenced block.

markdownlint flagged this. text renders fine for the directory layout.

-```
+```text
 /tmp/pr-<N>-visuals/
 ├── scope.md                  # phase 1 output
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

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

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/pr-visual-writeup/SKILL.md around lines 129 - 137,
Markdownlint flagged MD040 for the directory tree fenced code block in
.agents/skills/pr-visual-writeup/SKILL.md (the block starting with
"/tmp/pr-<N>-visuals/"); fix it by adding a language identifier to the opening
fence (e.g., change the opening "```" to "```text") so the block becomes a
labeled code block, ensure the closing fence remains present, and apply the same
fix to any other unlabeled fenced blocks in that file.

@greptile-apps

greptile-apps Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a pr-visual-writeup agent skill under the cross-client .agents/skills/ convention and symlinks .claude/skills → .agents/skills so Claude Code picks it up automatically. The skill orchestrates a five-phase pipeline: scope the PR diff, fan out browser-capture subagents in parallel across theme/viewport combinations, convert WebM scroll clips to GIFs via ffmpeg, push all assets to a PAT-only GitHub gist, and compose/set the PR body with inline screenshots.

Confidence Score: 5/5

Safe to merge; all findings are P2 style/reliability suggestions in helper scripts that don't affect core skill correctness.

Both flagged issues (wait exit-status masking in convert_clips.sh and missing lsof guard in detect_dev_server.sh) are P2 quality improvements. No correctness, data-integrity, or security issues were found. The credential-helper pattern in upload_gist.sh is intentional and documented.

scripts/convert_clips.sh and scripts/detect_dev_server.sh have minor robustness gaps worth addressing in a follow-up.

Important Files Changed

Filename Overview
.agents/skills/pr-visual-writeup/SKILL.md Main skill definition with 5-phase pipeline (scope → parallel capture → process → gist upload → compose/set); well-structured with clear trigger conditions and trust-boundary documentation.
.agents/skills/pr-visual-writeup/references/capture-patterns.md Subagent prompt template and frame-stitch scroll animation recipe; clear and accurate, no issues.
.agents/skills/pr-visual-writeup/references/gist-upload.md Documents PAT-only gist upload mechanism, flat namespace caveat, and raw URL shape; accurate and complete.
.agents/skills/pr-visual-writeup/references/pr-body-template.md Markdown template for PR body with light/dark screenshot tables; covers anti-patterns (no inline WebM, no gist page links) clearly.
.agents/skills/pr-visual-writeup/scripts/convert_clips.sh Parallel WebM→GIF converter using ffmpeg; wait only returns the last job's exit code so intermediate conversion failures are silently swallowed.
.agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh Detects running Node dev servers via lsof; lacks an explicit lsof dependency check, so a missing binary produces a misleading "no servers found" message instead of a clear error.
.agents/skills/pr-visual-writeup/scripts/upload_gist.sh End-to-end gist create → clone → stage → PAT-push → URL print pipeline; credential helper pattern is correct and intentionally transient.
.claude/skills Symlink pointing .claude/skills → .agents/skills so Claude Code discovers the shared skill directory.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([User invokes pr-visual-writeup skill]) --> B[Phase 1: Scope\ngh pr diff · detect_dev_server.sh\nwrite /tmp/pr-N-visuals/scope.md]
    B --> C[Phase 2: Parallel Capture\nSpawn N subagents in ONE message\none per theme × viewport]
    C --> D1[light-standard\n1920×1200]
    C --> D2[dark-standard\n1920×1200]
    C --> D3[light-wide\n2560×1440]
    C --> D4[dark-wide\n2560×1440]
    D1 & D2 & D3 & D4 --> E[Phase 3: Process\nconvert_clips.sh\nWebM → GIF in parallel]
    E --> F[Phase 4: Upload\nupload_gist.sh\nPAT git-push → raw URLs]
    F --> G[Phase 5: Compose + Set\npr-body-template.md\ngh pr edit --body-file]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .agents/skills/pr-visual-writeup/scripts/convert_clips.sh
Line: 34-35

Comment:
**`wait` silently drops intermediate ffmpeg failures**

In bash, `wait` (no arguments) returns the exit status of the *last* background process, not a logical OR of all of them. If, say, the second-to-last conversion fails due to a corrupt source file but the last one succeeds, `wait` returns 0, the `set -e` guard never fires, and the script prints `done.` despite missing GIFs. Consider collecting exit statuses explicitly:

```suggestion
wait
# Collect per-job exit codes
status=0
for pid in "${pids[@]}"; do
  wait "$pid" || status=$?
done
[ $status -ne 0 ] && echo "one or more conversions failed" >&2
echo "done."
```

This requires accumulating PIDs into a `pids=()` array inside the loop (`pids+=($!)`), but gives callers a reliable non-zero exit on partial failure.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: .agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh
Line: 19-27

Comment:
**Missing `lsof` dependency check gives a misleading exit message**

Unlike `convert_clips.sh`'s explicit `ffmpeg` guard, this script pipes `lsof 2>/dev/null` without verifying `lsof` is installed. If `lsof` is absent, bash emits "command not found" to stderr (silenced), the pipeline yields empty output, and the user sees `no listening node servers in 3000-9999` — which looks like a runtime result rather than a missing-tool error.

```suggestion
if ! command -v lsof >/dev/null 2>&1; then
  echo "lsof not found. Install with: brew install lsof  (or your distro's package manager)" >&2
  exit 1
fi

# Collect every node-listened TCP port in the range.
ports=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null \
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Symlink .claude/skills -> .agents/skills" | Re-trigger Greptile

Comment on lines +34 to +35
wait
echo "done."

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.

P2 wait silently drops intermediate ffmpeg failures

In bash, wait (no arguments) returns the exit status of the last background process, not a logical OR of all of them. If, say, the second-to-last conversion fails due to a corrupt source file but the last one succeeds, wait returns 0, the set -e guard never fires, and the script prints done. despite missing GIFs. Consider collecting exit statuses explicitly:

Suggested change
wait
echo "done."
wait
# Collect per-job exit codes
status=0
for pid in "${pids[@]}"; do
wait "$pid" || status=$?
done
[ $status -ne 0 ] && echo "one or more conversions failed" >&2
echo "done."

This requires accumulating PIDs into a pids=() array inside the loop (pids+=($!)), but gives callers a reliable non-zero exit on partial failure.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .agents/skills/pr-visual-writeup/scripts/convert_clips.sh
Line: 34-35

Comment:
**`wait` silently drops intermediate ffmpeg failures**

In bash, `wait` (no arguments) returns the exit status of the *last* background process, not a logical OR of all of them. If, say, the second-to-last conversion fails due to a corrupt source file but the last one succeeds, `wait` returns 0, the `set -e` guard never fires, and the script prints `done.` despite missing GIFs. Consider collecting exit statuses explicitly:

```suggestion
wait
# Collect per-job exit codes
status=0
for pid in "${pids[@]}"; do
  wait "$pid" || status=$?
done
[ $status -ne 0 ] && echo "one or more conversions failed" >&2
echo "done."
```

This requires accumulating PIDs into a `pids=()` array inside the loop (`pids+=($!)`), but gives callers a reliable non-zero exit on partial failure.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +19 to +27
ports=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null \
| awk '/^node/ {print $9}' \
| grep -oE ':[0-9]+$' \
| tr -d ':' \
| sort -u \
| awk -v min="$MIN" -v max="$MAX" '$1 >= min && $1 <= max')

if [ -z "$ports" ]; then
echo "no listening node servers in $MIN-$MAX" >&2

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.

P2 Missing lsof dependency check gives a misleading exit message

Unlike convert_clips.sh's explicit ffmpeg guard, this script pipes lsof 2>/dev/null without verifying lsof is installed. If lsof is absent, bash emits "command not found" to stderr (silenced), the pipeline yields empty output, and the user sees no listening node servers in 3000-9999 — which looks like a runtime result rather than a missing-tool error.

Suggested change
ports=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null \
| awk '/^node/ {print $9}' \
| grep -oE ':[0-9]+$' \
| tr -d ':' \
| sort -u \
| awk -v min="$MIN" -v max="$MAX" '$1 >= min && $1 <= max')
if [ -z "$ports" ]; then
echo "no listening node servers in $MIN-$MAX" >&2
if ! command -v lsof >/dev/null 2>&1; then
echo "lsof not found. Install with: brew install lsof (or your distro's package manager)" >&2
exit 1
fi
# Collect every node-listened TCP port in the range.
ports=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null \
Prompt To Fix With AI
This is a comment left during a code review.
Path: .agents/skills/pr-visual-writeup/scripts/detect_dev_server.sh
Line: 19-27

Comment:
**Missing `lsof` dependency check gives a misleading exit message**

Unlike `convert_clips.sh`'s explicit `ffmpeg` guard, this script pipes `lsof 2>/dev/null` without verifying `lsof` is installed. If `lsof` is absent, bash emits "command not found" to stderr (silenced), the pipeline yields empty output, and the user sees `no listening node servers in 3000-9999` — which looks like a runtime result rather than a missing-tool error.

```suggestion
if ! command -v lsof >/dev/null 2>&1; then
  echo "lsof not found. Install with: brew install lsof  (or your distro's package manager)" >&2
  exit 1
fi

# Collect every node-listened TCP port in the range.
ports=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null \
```

How can I resolve this? If you propose a fix, please make it concise.

@BilalG1
BilalG1 merged commit dad752a into dev Apr 20, 2026
41 of 43 checks passed
@BilalG1
BilalG1 deleted the add-pr-visual-writeup-skill branch April 20, 2026 18:54

This branch was successfully deployed

2 active deployments
Preview – stack-preview-backend — cf609027 Deployed Apr 20, 2026 by vercel[bot]
Preview – stack-preview-dashboard — cf609027 Deployed Apr 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant