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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/favicons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/favicons/favicon-180x180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/favicons/favicon-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/favicons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/favicons/favicon-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions assets/favicons/site.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "SolFoundry",
"short_name": "SolFoundry",
"description": "Autonomous AI Software Factory on Solana",
"start_url": "/",
"display": "standalone",
"theme_color": "#6366f1",
"background_color": "#0a0a0a",
"icons": [
{
"src": "/assets/favicons/favicon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/favicons/favicon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
}
]
}
7 changes: 7 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SolFoundry — Autonomous AI Software Factory on Solana</title>
<!-- Favicons (generated from assets/logo-icon.svg) -->
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="192x192" href="/assets/favicons/favicon-192x192.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/favicon-180x180.png">
<link rel="manifest" href="/assets/favicons/site.webmanifest">
<meta name="theme-color" content="#6366f1">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
* {
Expand Down
43 changes: 43 additions & 0 deletions scripts/generate-favicons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
#
# generate-favicons.sh — Convert assets/logo-icon.svg into browser-ready
# favicon PNGs at 16×16, 32×32, 180×180 (apple-touch), 192×192 and 512×512.
#
# Dependencies:
# rsvg-convert (librsvg2-bin on Debian, librsvg on Homebrew)
#
# Usage:
# ./scripts/generate-favicons.sh
#
# Output: assets/favicons/favicon-{16x16,32x32,180x180,192x192,512x512}.png

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
SOURCE_SVG="$ROOT_DIR/assets/logo-icon.svg"
OUT_DIR="$ROOT_DIR/assets/favicons"

if [[ ! -f "$SOURCE_SVG" ]]; then
printf 'Error: source SVG not found at %s\n' "$SOURCE_SVG" >&2
exit 1
fi

if ! command -v rsvg-convert >/dev/null 2>&1; then
printf 'Error: rsvg-convert is required.\n' >&2
printf ' macOS: brew install librsvg\n' >&2
printf ' Debian: apt install librsvg2-bin\n' >&2
exit 1
fi

mkdir -p "$OUT_DIR"

SIZES=(16 32 180 192 512)

for size in "${SIZES[@]}"; do
rsvg-convert -w "$size" -h "$size" "$SOURCE_SVG" \
-o "$OUT_DIR/favicon-${size}x${size}.png"
printf ' ✓ favicon-%sx%s.png\n' "$size" "$size"
done

printf '\nDone — %d PNGs written to %s/\n' "${#SIZES[@]}" "$OUT_DIR"
125 changes: 125 additions & 0 deletions scripts/test-favicons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env bash
#
# test-favicons.sh — Validate favicon assets, HTML integration, and manifest.
#
# Runs 29 assertions that verify every acceptance criterion from issue #471:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assertion count discrepancy: comment claims 29 but script contains 27.

Line 5 states "Runs 29 assertions" but counting the actual assert* calls:

  • Section 1 (PNG files): 7 assertions (lines 74-80)
  • Section 2 (Manifest): 7 assertions (lines 85-91)
  • Section 3 (HTML head): 8 assertions (lines 96-103)
  • Section 4 (Generation script): 4 assertions (lines 108-111)
  • Section 5 (Consistency): 1 assertion (line 116)

Total: 27 assertions, not 29. Update the comment to reflect the actual count.

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

In `@scripts/test-favicons.sh` at line 5, Update the top comment in the
test-favicons.sh script to correctly state the number of assertions: change the
line that currently reads "Runs 29 assertions" to "Runs 27 assertions" so the
comment matches the actual count of assert* calls (the various assert* lines in
Sections 1–5 of the script).

# 1. PNGs exist at 16×16, 32×32, 180×180, 192×192, 512×512
# 2. site.webmanifest references the correct icons
# 3. index.html <head> contains all required <link> tags
# 4. Generation script is present and well-formed
# 5. No stale or mismatched references
#
# Usage:
# ./scripts/test-favicons.sh
#
# Exit 0 when all assertions pass, 1 otherwise.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
FAVICONS="$ROOT_DIR/assets/favicons"
INDEX="$ROOT_DIR/index.html"
MANIFEST="$FAVICONS/site.webmanifest"
GEN_SCRIPT="$SCRIPT_DIR/generate-favicons.sh"

PASS=0
FAIL=0

# ── helpers ───────────────────────────────────────────────────────────────────

assert() {
# Run a command; record pass/fail.
local desc="$1"; shift
if "$@" >/dev/null 2>&1; then
printf ' ✅ %s\n' "$desc"
PASS=$((PASS + 1))
else
printf ' ❌ %s\n' "$desc"
FAIL=$((FAIL + 1))
fi
}

assert_file() {
# Verify a file exists.
assert "Exists: $1" test -f "$1"
}

assert_min_bytes() {
# Verify file is at least N bytes (handles missing files gracefully).
local file="$1" min="$2" label="$3"
if [[ ! -f "$file" ]]; then
printf ' ❌ %s — file not found\n' "$label"
FAIL=$((FAIL + 1))
return
fi
local actual
actual=$(wc -c < "$file")
assert "$label (${actual}B >= ${min}B)" test "$actual" -ge "$min"
}

assert_grep() {
# Verify a pattern appears in a file.
assert "$1" grep -q "$2" "$3"
}

assert_no_grep() {
# Verify a pattern does NOT appear in a file.
assert "$1" sh -c "! grep -q '$2' '$3'"
}
Comment on lines +31 to +69
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Test helper functions are well-designed with minor shell quoting concern.

The assertion helpers properly track pass/fail counts and handle missing files gracefully in assert_min_bytes.

Minor note on line 68: The pattern sh -c "! grep -q '$2' '$3'" uses single quotes inside double quotes. If $2 ever contained a single quote, it would break the command. In this controlled script context where patterns are hardcoded, this is not exploitable, but a more robust approach would use:

assert_no_grep() {
  assert "$1" sh -c '! grep -q "$1" "$2"' _ "$2" "$3"
}

This is a defensive improvement, not a blocking issue.

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

In `@scripts/test-favicons.sh` around lines 31 - 69, The assert_no_grep helper
uses sh -c with embedded single quotes which can break if the pattern ($2)
contains a single quote; update the assert_no_grep function to pass the pattern
and filename as positional arguments to sh -c instead of interpolating them,
e.g. call sh -c with a command string like '! grep -q "$1" "$2"' and supply a
dummy $0 followed by the pattern and file as arguments so grep gets safe,
properly-quoted parameters; edit the assert_no_grep function accordingly to use
this argument-passing form.

Comment on lines +66 to +69
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Dead code: assert_no_grep is defined but never used.

The assert_no_grep helper function is implemented but has no callers in the script. Either remove it to reduce maintenance burden, or add the intended negative assertions it was designed for (e.g., verifying no stale references as mentioned in the header comment on line 10).

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

In `@scripts/test-favicons.sh` around lines 66 - 69, Remove the dead helper
function assert_no_grep (and its inner call to assert with sh -c "! grep -q '$2'
'$3'") since it's never used; if you actually intended negative checks, instead
add explicit calls to assert_no_grep at the appropriate places (e.g., to verify
no stale references) or inline the negative assertion using assert sh -c "! grep
-q 'PATTERN' 'FILE'" where needed—either delete the unused assert_no_grep
definition or add the specific assert_no_grep(...) calls that perform the
intended negative checks.


# ── 1. PNG assets ─────────────────────────────────────────────────────────────

printf '\n[1/5] Favicon PNG files\n'
assert_file "$FAVICONS/favicon-16x16.png"
assert_file "$FAVICONS/favicon-32x32.png"
assert_file "$FAVICONS/favicon-180x180.png"
assert_file "$FAVICONS/favicon-192x192.png"
assert_file "$FAVICONS/favicon-512x512.png"
assert_min_bytes "$FAVICONS/favicon-16x16.png" 100 "16×16 PNG non-trivial"
assert_min_bytes "$FAVICONS/favicon-512x512.png" 1000 "512×512 PNG non-trivial"

# ── 2. site.webmanifest ──────────────────────────────────────────────────────

printf '\n[2/5] Web app manifest\n'
assert_file "$MANIFEST"
assert_grep "Manifest → 192×192 icon" "favicon-192x192.png" "$MANIFEST"
assert_grep "Manifest → 512×512 icon" "favicon-512x512.png" "$MANIFEST"
assert_grep "Manifest → app name" "SolFoundry" "$MANIFEST"
assert_grep "Manifest → purpose field" '"purpose"' "$MANIFEST"
assert_grep "Manifest → display mode" '"standalone"' "$MANIFEST"
assert_grep "Manifest → theme_color" "theme_color" "$MANIFEST"

# ── 3. index.html <head> tags ────────────────────────────────────────────────

printf '\n[3/5] HTML <head> integration\n'
assert_file "$INDEX"
assert_grep "Link → 16×16 PNG" 'favicon-16x16.png' "$INDEX"
assert_grep "Link → 32×32 PNG" 'favicon-32x32.png' "$INDEX"
assert_grep "Link → 192×192 PNG" 'favicon-192x192.png' "$INDEX"
assert_grep "Link → apple-touch-icon" 'apple-touch-icon' "$INDEX"
assert_grep "Link → manifest" 'site.webmanifest' "$INDEX"
assert_grep "Meta → theme-color" 'theme-color' "$INDEX"
assert_grep "MIME type image/png" 'image/png' "$INDEX"

# ── 4. Generation script ─────────────────────────────────────────────────────

printf '\n[4/5] Generation script\n'
assert_file "$GEN_SCRIPT"
assert "Script is executable" test -x "$GEN_SCRIPT"
assert_grep "Script uses rsvg-convert" 'rsvg-convert' "$GEN_SCRIPT"
assert_grep "Script references logo-icon.svg" 'logo-icon.svg' "$GEN_SCRIPT"

# ── 5. Consistency checks ────────────────────────────────────────────────────

printf '\n[5/5] Cross-file consistency\n'
assert_grep "Manifest paths start with /" '"/assets/favicons/' "$MANIFEST"

# ── summary ───────────────────────────────────────────────────────────────────

printf '\n══ Results: %d passed, %d failed ══\n' "$PASS" "$FAIL"

if [[ "$FAIL" -gt 0 ]]; then
exit 1
fi
printf 'All tests passed.\n'
Loading