Compare commits
4
Commits
1fe932cf39
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
999cd7d6b8 | ||
|
|
f5f6d2322a | ||
|
|
a03dcc9e7e | ||
|
|
ba7f5e7d06 |
+11
-1
@@ -32,7 +32,7 @@ contact details and GPG public keys.
|
||||
| Build | `build.sh`: md5 content-hash cache-busting + `sed` reference rewrites → `dist/` | md5 is a cache key, not a security hash — acceptable | LOCKED (pre-existing) |
|
||||
| Serving | `nginx:alpine`, `listen 8080`, plain HTTP | TLS is added by the Caddy edge in front of the container | LOCKED (pre-existing) |
|
||||
| Edge | Caddy reverse proxy (Route53 DNS-validated TLS) in front of the container | HSTS/TLS are edge responsibilities | LOCKED (assumed — verify per Phase 03) |
|
||||
| E2E tests | `@playwright/test` pinned **1.62.0** (matches cached chromium-1234), serves `dist/` via `python3 -m http.server 8123`, config `playwright.config.js` | Tests the deployed artifact; pinned to avoid browser re-downloads | LOCKED (2026-09-18, user-approved) |
|
||||
| E2E tests | `@playwright/test` pinned **1.63.0** (matches cached chromium-1243), serves `dist/` via `python3 -m http.server 8123`, config `playwright.config.js` | Tests the deployed artifact; pinned to avoid browser re-downloads | LOCKED (2026-09-18; re-pinned 2026-09-18, user-approved — see review history) |
|
||||
| Deployment | Docker image → `gitea.reeseapps.com/services/homepage` via Gitea Actions (secrets-based registry login) | Self-hosted CI | LOCKED (pre-existing) |
|
||||
| Persistence | `localStorage` only (achievements, key `reese-terminal-achievements`) | No backend by design | LOCKED (pre-existing) |
|
||||
|
||||
@@ -110,3 +110,13 @@ Caddy edge — folded into Phase 03 verification), L-3 (drop
|
||||
L-5 (label the displayed SSH key as fictitious or show fingerprint only),
|
||||
L-7 (pin CI action SHAs / image signing), L-8 (build.sh verification test in
|
||||
CI).
|
||||
|
||||
## 8. Review History
|
||||
|
||||
- **2026-09-18** — Security & code-quality audit; module split and the
|
||||
`@playwright/test` 1.62.0 / chromium-1234 pin approved.
|
||||
- **2026-09-18** — User-approved dependency update: `@playwright/test`
|
||||
bumped 1.62.0 → 1.63.0; §3 lock re-pinned to 1.63.0 (matches cached
|
||||
chromium-1243, re-downloaded locally). Full 44-test E2E suite green on
|
||||
1.63.0. Executed as a direct change per explicit user instruction
|
||||
(no phase).
|
||||
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# .agents/validate.sh — validation gate for the phased-execution pipeline.
|
||||
#
|
||||
# A unit is only moved to .agents/phases/complete/ if this script exits 0,
|
||||
# and a phase is only COMMITTED if its final pass exits 0 — so this script
|
||||
# is the last line of defense for "no phase commits unless 100% passing".
|
||||
# It MUST run the project's FULL test suite (every test, not a subset) plus
|
||||
# its linter, so a failure anywhere in the project blocks the commit.
|
||||
#
|
||||
# Adapt the checks below to this project's real test suite, linter, and
|
||||
# coverage floor, then commit the result.
|
||||
set -uo pipefail
|
||||
rc=0
|
||||
|
||||
if [[ -f pyproject.toml || -f pytest.ini || -f setup.py ]]; then
|
||||
python3 -m pytest -q || rc=1
|
||||
if command -v ruff >/dev/null 2>&1; then
|
||||
ruff check . || rc=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -f package.json ]]; then
|
||||
npm test --silent || rc=1
|
||||
fi
|
||||
|
||||
# --- project-specific gate: container security headers (Phase 03, audit M-4) --
|
||||
# Builds the real nginx image and asserts all four hardening headers on every
|
||||
# response class (/, /index.html, a hashed asset). Needs a container runtime;
|
||||
# if the host has none the check is skipped loudly instead of failing silently.
|
||||
if [[ -x scripts/check-headers.sh ]]; then
|
||||
if command -v podman >/dev/null 2>&1; then RT=podman
|
||||
elif command -v docker >/dev/null 2>&1; then RT=docker
|
||||
else RT=""
|
||||
fi
|
||||
if [[ -n "$RT" ]]; then
|
||||
./scripts/check-headers.sh || rc=1
|
||||
# check-headers.sh removes its container but not its scratch image tag;
|
||||
# drop it here so repeated gates do not fill container storage.
|
||||
leftovers="$("$RT" images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep 'homepage-headercheck-' || true)"
|
||||
if [[ -n "$leftovers" ]]; then
|
||||
printf '%s\n' "$leftovers" | xargs -r "$RT" rmi -f >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
echo "WARN: no podman/docker available — SKIPPING scripts/check-headers.sh (security-header gate not exercised)" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- repo hygiene (language-agnostic; runs in every project) ------------------
|
||||
# Scoped staging commits everything the phase touched, so a file that is not
|
||||
# ignored gets committed — including raw log drops and key material. These
|
||||
# gates make the phase fail instead. Fix by untracking, keeping the working
|
||||
# copy: git rm --cached <file>
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
# 1. A tracked file that matches a .gitignore rule should never be tracked.
|
||||
junk="$(git ls-files -i -c --exclude-standard 2>/dev/null || true)"
|
||||
if [[ -n "$junk" ]]; then
|
||||
echo "repo hygiene: TRACKED files match .gitignore rules (untrack with 'git rm --cached <file>'):" >&2
|
||||
printf ' %s\n' "$junk" >&2
|
||||
rc=1
|
||||
fi
|
||||
|
||||
# 2. Personal-data / key-material file SHAPES that must never be tracked,
|
||||
# even in a project with no .gitignore rule for them.
|
||||
DANGEROUS='(^|/)[^/]*\.log$|(^|/)[^/]*\.jsonl$|(^|/)\.env($|\.)|\.(pem|key|crt|cer|p12|pfx|keystore|jks)$|(^|/)(id_rsa|id_ecdsa|id_ed25519)(\.pub)?$|(^|/)(credentials|service-account|client_secret)([-a-z0-9]*)\.json$'
|
||||
bad="$(git ls-files | grep -E "$DANGEROUS" || true)"
|
||||
if [[ -n "$bad" ]]; then
|
||||
echo "repo hygiene: TRACKED files look like log drops / key material (untrack with 'git rm --cached <file>' and add a .gitignore rule):" >&2
|
||||
printf ' %s\n' "$bad" >&2
|
||||
rc=1
|
||||
fi
|
||||
|
||||
# 3. Project-specific content scan for personal data inside tracked files
|
||||
# (client IPs, account ids, ...). Empty by default — fill it in per
|
||||
# project, and allow-list documentation ranges (RFC 5737 / 4193 / 3849,
|
||||
# 127.0.0.0/8, RFC1918) so fixtures do not trip it. Format: one ERE.
|
||||
PII_PATTERNS="${PII_PATTERNS:-}"
|
||||
if [[ -n "$PII_PATTERNS" ]]; then
|
||||
hits="$(git ls-files -z | xargs -0 grep -IHnE "$PII_PATTERNS" 2>/dev/null || true)"
|
||||
if [[ -n "$hits" ]]; then
|
||||
echo "personal-data gate: TRACKED files match PII_PATTERNS — redact them:" >&2
|
||||
printf ' %s\n' "$hits" >&2
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $rc -ne 0 ]]; then
|
||||
echo "validation FAILED (see output above)"
|
||||
fi
|
||||
exit "$rc"
|
||||
@@ -16,9 +16,15 @@ Rules for any agent working in this repository.
|
||||
- `./build.sh` — rebuild `dist/` (tests run against `dist/`, the
|
||||
deployed artifact — never test `src/` directly).
|
||||
- `npm test` — the Playwright E2E suite (pinned `@playwright/test`
|
||||
1.62.0; do not bump without re-checking the cached browser revision).
|
||||
- For any nginx/Dockerfile change: `./scripts/check-headers.sh`
|
||||
(Phase 03+).
|
||||
1.63.0; do not bump without re-checking the cached browser revision).
|
||||
- `.agents/validate.sh` — the pipeline gate: full E2E suite + the container
|
||||
security-header check + repo-hygiene checks; must exit 0 before a phase is
|
||||
committed.
|
||||
- For any `nginx.conf` / `nginx-security-headers.inc` / Dockerfile change:
|
||||
`./scripts/check-headers.sh` (added by Phase 03, run automatically by
|
||||
`.agents/validate.sh` when a container runtime exists). It builds the real
|
||||
image, serves it on `127.0.0.1:18099` and must print
|
||||
`HEADER CHECK PASSED`; don't substitute a hand-rolled `curl` for it.
|
||||
|
||||
## Never
|
||||
- Modify `.agents/PLAN.md` except via an explicit user-approved change to the
|
||||
@@ -37,6 +43,36 @@ Rules for any agent working in this repository.
|
||||
- Static site: edits in `src/` → `./build.sh` → `dist/` (hash-cached names).
|
||||
New root-level assets are picked up automatically by `build.sh`; nested
|
||||
directories are **not** (keep JS files flat in `src/`).
|
||||
- Terminal input is untrusted: never render typed input or `commandHistory`
|
||||
with `innerHTML` — route it through `updateDisplay()`/`textContent`
|
||||
(audit M-1, guarded by the markup-payload test in
|
||||
`tests/e2e/02-terminal.spec.js`). The only `innerHTML` uses allowed in
|
||||
`src/terminal.js` are static prompt literals, the `clear`/prank element
|
||||
wipes, and the canned `neofetch` output (the `cmdText === 'neofetch'` branch —
|
||||
every other command output goes through `textContent`). In
|
||||
`terminal-vim.js`/`terminal-achievements.js` `innerHTML` is acceptable only
|
||||
with static markup or `escapeHtml()`-escaped text.
|
||||
- The fake terminal does zero network I/O: `curl`/`wget` render canned output
|
||||
from `simulatedCurlOutput()` / `simulatedWgetOutput()` in
|
||||
`src/terminal-commands.js` (pure string builders, no DOM, no network). Keep
|
||||
any browser-side fetch call out of `src/` entirely (audit M-2, Phase 02).
|
||||
Guarded by the curl/wget regression test in `tests/e2e/02-terminal.spec.js`,
|
||||
which records every request whose URL falls outside `baseURL` from
|
||||
`playwright.config.js` and fails the suite if the list is not empty.
|
||||
- Security headers live in `nginx-security-headers.inc` (the Dockerfile copies
|
||||
it to `/etc/nginx/snippets/security-headers.inc`) and **every** `location` in
|
||||
`nginx.conf` `include`s it. nginx does not merge `add_header` across
|
||||
configuration levels, so never rely on server-level inheritance and never add
|
||||
inline security `add_header` lines to `nginx.conf` — put them in the snippet
|
||||
(audit M-4, Phase 03). `server_tokens off;` stays in the `server` block
|
||||
(audit L-2). `scripts/check-headers.sh` guards this rule: drop one `include`
|
||||
from a location and the check fails for that path.
|
||||
- Featured-projects content is test-locked: the `#projects` grid in
|
||||
`src/index.html` (six cards in a fixed order — Brain of Reese first with its
|
||||
Gitea source link, ServWaf last with no link because it is closed source) is
|
||||
asserted by the `featured projects show the six updated cards in order` test
|
||||
in `tests/e2e/01-page.spec.js`. Edit the cards in `src/index.html` and update
|
||||
that test in the same change (Phase 05).
|
||||
- Terminal modules: `terminal-commands.js` (canned data),
|
||||
`terminal-achievements.js`, `terminal-vim.js`, `terminal.js` (core) — load
|
||||
order is fixed in `index.html` (all `defer`); keep dependencies pointing
|
||||
|
||||
Generated
+12
-30
@@ -8,17 +8,17 @@
|
||||
"name": "homepage",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.62.0"
|
||||
"@playwright/test": "1.63.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.0.tgz",
|
||||
"integrity": "sha512-9zOJ6ZQRAena31MpOH9VSzIz8Ou3YJ/wtY/eQm5T2uhfhG7/U3COrMS8xOtUrZrp9OgdmzEnIYODye3nY1VqzA==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz",
|
||||
"integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.62.0"
|
||||
"playwright": "1.63.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -27,44 +27,26 @@
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.0.tgz",
|
||||
"integrity": "sha512-Z14dG305dgaLu6foB1TXQagFiW8JfSUIUaUuPaKQ6NtBPKF1P/qXcqfh6c6K/icPqdy37JmjbiBXf6JNg6Sylw==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
|
||||
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.62.0"
|
||||
"playwright-core": "1.63.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.0.tgz",
|
||||
"integrity": "sha512-nsNRyq0r2zsG8AcRHWknc9QRA5XCueC7gWMrs+Gx2tlZn9hcl8zudfh00lhJPY1DE7NmZ6bDsT9g2yey8mXljA==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
|
||||
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
||||
+1
-1
@@ -9,6 +9,6 @@
|
||||
"test:headed": "playwright test --headed"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.62.0"
|
||||
"@playwright/test": "1.63.0"
|
||||
}
|
||||
}
|
||||
|
||||
+49
-49
@@ -117,14 +117,14 @@
|
||||
</div>
|
||||
<span class="timeline-date">Jun 2026 – Present</span>
|
||||
<ul class="timeline-list">
|
||||
<li>Building an enterprise agentic vulnerability remediation
|
||||
toolkit and workflow to resolve millions of vulnerabilities.</li>
|
||||
<li>Creating and distributing LLM harness skills that automate
|
||||
business problems — including ServiceNow incident response —
|
||||
<li>Built an enterprise agentic vulnerability remediation toolkit
|
||||
and workflow to resolve millions of vulnerabilities.</li>
|
||||
<li>Created and distributed LLM harness skills that automate
|
||||
business problems - including ServiceNow incident response -
|
||||
at machine speed.</li>
|
||||
<li>Leading a team of 6 offshore engineers to build a developer
|
||||
landing zone with agentic tools that build pipelines, plan
|
||||
work, and make documentation searchable.</li>
|
||||
<li>Led a team of 6 offshore engineers building a developer landing
|
||||
zone with agentic tools that build pipelines, plan work, and
|
||||
make documentation searchable.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -137,7 +137,7 @@
|
||||
</div>
|
||||
<span class="timeline-date">Jan 2022 – Apr 2026</span>
|
||||
<ul class="timeline-list">
|
||||
<li>Lead a high-performing DevOps team building microelectronics design services and
|
||||
<li>Led a high-performing DevOps team building microelectronics design services and
|
||||
integrating cloud partner architectures with AWS.</li>
|
||||
<li>Recruited and led an engineering team to deliver a machine learning platform in <1
|
||||
year, utilizing Langchain, PyTorch, and BERT to identify government contract patterns.
|
||||
@@ -308,7 +308,7 @@
|
||||
</div>
|
||||
<div class="project-info">
|
||||
<h3>Brain of Reese</h3>
|
||||
<p>A chippy, honest RAG chatbot over homelab documentation — git repositories, local
|
||||
<p>A chippy, honest RAG chatbot over homelab documentation - git repositories, local
|
||||
directories, and uploaded archives. Hybrid search (pgvector cosine ∪ Postgres
|
||||
full-text search, Reciprocal Rank Fusion) feeds the whole relevant document to a
|
||||
self-hosted LLM and streams back a grounded answer; when it has no notes it
|
||||
@@ -332,6 +332,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="code-comment"># Inference engines</span></div>
|
||||
<div class="code-line"><span class="code-variable">engines</span> = {</div>
|
||||
<div class="code-line"> <span class="code-string">"vllm"</span>: <span class="code-string">"cuda"</span>, <span class="code-comment"># high-throughput serving</span></div>
|
||||
<div class="code-line"> <span class="code-string">"gufo"</span>: <span class="code-string">"rocm"</span>, <span class="code-comment"># Strix Halo inference</span></div>
|
||||
<div class="code-line"> <span class="code-string">"llama.cpp"</span>: <span class="code-string">"gguf"</span>, <span class="code-comment"># CPU/GPU fallback</span></div>
|
||||
<div class="code-line">}</div>
|
||||
<div class="code-line"> </div>
|
||||
<div class="code-line"><span class="code-comment"># LiteLLM proxy for unified API</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-info">
|
||||
<h3>Local AI Stack</h3>
|
||||
<p>Complete local AI infrastructure: vLLM, Gufo, and llama.cpp for inference, LiteLLM as a
|
||||
unified API proxy, Bifrost for model routing, and Langfuse for observability. Supports
|
||||
both CUDA and ROCm.</p>
|
||||
<div class="project-meta">
|
||||
<div class="project-tech">
|
||||
<span>vLLM</span>
|
||||
<span>Gufo</span>
|
||||
<span>llama.cpp</span>
|
||||
<span>LocalAI</span>
|
||||
<span>LiteLLM</span>
|
||||
<span>Langfuse</span>
|
||||
</div>
|
||||
<div class="project-links">
|
||||
<a href="https://gitea.reeseapps.com/services/homelab" title="Source" target="_blank"
|
||||
rel="noopener">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
@@ -421,45 +460,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="code-comment"># Inference engines</span></div>
|
||||
<div class="code-line"><span class="code-variable">engines</span> = {</div>
|
||||
<div class="code-line"> <span class="code-string">"vllm"</span>: <span class="code-string">"cuda"</span>, <span class="code-comment"># high-throughput serving</span></div>
|
||||
<div class="code-line"> <span class="code-string">"gufo"</span>: <span class="code-string">"rocm"</span>, <span class="code-comment"># Strix Halo inference</span></div>
|
||||
<div class="code-line"> <span class="code-string">"llama.cpp"</span>: <span class="code-string">"gguf"</span>, <span class="code-comment"># CPU/GPU fallback</span></div>
|
||||
<div class="code-line">}</div>
|
||||
<div class="code-line"> </div>
|
||||
<div class="code-line"><span class="code-comment"># LiteLLM proxy for unified API</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-info">
|
||||
<h3>Local AI Stack</h3>
|
||||
<p>Complete local AI infrastructure: vLLM, Gufo, and llama.cpp for inference, LiteLLM as a
|
||||
unified API proxy, Bifrost for model routing, and Langfuse for observability. Supports
|
||||
both CUDA and ROCm.</p>
|
||||
<div class="project-meta">
|
||||
<div class="project-tech">
|
||||
<span>vLLM</span>
|
||||
<span>Gufo</span>
|
||||
<span>llama.cpp</span>
|
||||
<span>LocalAI</span>
|
||||
<span>LiteLLM</span>
|
||||
<span>Langfuse</span>
|
||||
</div>
|
||||
<div class="project-links">
|
||||
<a href="https://gitea.reeseapps.com/services/homelab" title="Source" target="_blank"
|
||||
rel="noopener">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
@@ -505,7 +505,7 @@
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="code-comment"># ServWaf — declarative rules</span></div>
|
||||
<div class="code-line"><span class="code-comment"># ServWaf - declarative rules</span></div>
|
||||
<div class="code-line"><span class="code-variable">ratelimit</span>:</div>
|
||||
<div class="code-line"> <span class="code-variable">per_ip</span>: <span
|
||||
class="code-string">20 rps, burst 40</span></div>
|
||||
|
||||
@@ -52,9 +52,9 @@ test.describe('Page structure', () => {
|
||||
const titles = await cards.locator('.project-info h3').allTextContents();
|
||||
expect(titles).toEqual([
|
||||
'Brain of Reese',
|
||||
'Local AI Stack',
|
||||
'Reverse Proxy Infrastructure',
|
||||
'Dynamic DNS Service',
|
||||
'Local AI Stack',
|
||||
'Deployment Automation',
|
||||
'ServWaf',
|
||||
]);
|
||||
@@ -63,8 +63,8 @@ test.describe('Page structure', () => {
|
||||
await expect(brain.locator('.project-tech span')).toHaveCount(4);
|
||||
await expect(brain).toHaveText(/RAG chatbot/i);
|
||||
await expect(brain.locator('a[href="https://gitea.reeseapps.com/Experimental/brain-of-reese"]')).toBeAttached();
|
||||
// Local AI Stack: Ollama replaced by vLLM, Gufo, llama.cpp
|
||||
const ai = cards.nth(3);
|
||||
// Local AI Stack: second card, Ollama replaced by vLLM, Gufo, llama.cpp
|
||||
const ai = cards.nth(1);
|
||||
await expect(ai.locator('.project-tech span')).toHaveText(['vLLM', 'Gufo', 'llama.cpp', 'LocalAI', 'LiteLLM', 'Langfuse']);
|
||||
await expect(ai).not.toContainText('Ollama');
|
||||
// ServWaf is closed source — description only, no source link
|
||||
|
||||
Reference in New Issue
Block a user