Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .agents/skills/publish-cover/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ What the script does deterministically:
| Stamp | `<!-- repo:<hash> built:<ISO-8601> -->` in every `.html` |
| Validate | Every `.gif` in dist: max file size, nonzero frame count |
| Scan | Secret scan across all dist files (rejects on match) |
| Local copy | Writes `LOCAL_COPY` — a committed, browsable snapshot of the built page |
| Report | Manifest + per-file sizes to stdout |

**Env overrides:**
Expand All @@ -91,6 +92,17 @@ What the script does deterministically:
| `COVER_DIST` | `dist-cover/` | Build output |
| `MAX_GIF_SIZE_MB` | `5` | Reject gifs larger than this |
| `SKIP_SECRET_SCAN` | `0` | `1` = bypass (escape hatch) |
| `LOCAL_COPY` | `docs/cover.html` | Repo-relative snapshot of the built page; `""` skips |

**On `LOCAL_COPY`:** do not hand-maintain a duplicate of the cover. The version
badge is injected *at build time*, so any manually edited copy is stale the
moment the version moves — and because the copy lands outside `COVER_DIST`, its
relative asset paths dangle (`docs/cover.html` shipped a broken hero image for
exactly this reason). The build emits it after the secret scan and re-points
each asset reference at `COVER_SRC`, relative to wherever the copy lands.
Anchors, absolute URLs, and refs that do not resolve in the source tree are
left untouched. Only `index.html` is mirrored — it is a snapshot, not a second
dist. Commit the result; never edit it by hand.

### Step 2 — Audit

Expand Down
38 changes: 38 additions & 0 deletions .agents/skills/publish-cover/scripts/build-cover-dist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ COVER_SRC="${COVER_SRC:-cover}"
COVER_DIST="${COVER_DIST:-dist-cover}"
MAX_GIF_SIZE_MB="${MAX_GIF_SIZE_MB:-5}"
SKIP_SECRET_SCAN="${SKIP_SECRET_SCAN:-0}"
# Repo-relative path for a committed, browsable snapshot of the built page.
# Set to "" to skip. This exists because a hand-maintained copy cannot stay
# correct: the version badge is injected here at build time, so any manually
# edited duplicate is stale the moment the version moves.
LOCAL_COPY="${LOCAL_COPY:-docs/cover.html}"

RED='\033[0;31m'
GREEN='\033[0;32m'
Expand Down Expand Up @@ -183,6 +188,39 @@ else:
echo "$HITS"
fi

# ── local copy ──────────────────────────────────────────────────────────────
# Emitted AFTER the secret scan so a copy is never committed with a leak the
# scan would have rejected. Asset references are re-pointed at COVER_SRC:
# the copy lands outside COVER_DIST, so every relative src/href in it would
# otherwise dangle (this is exactly how docs/cover.html shipped a broken hero
# image). Only index.html is mirrored — the copy is a browsable snapshot, not
# a second dist.

if [ -n "$LOCAL_COPY" ]; then
say "emitting local copy → ${LOCAL_COPY}"
python3 - "$COVER_DIST" "$COVER_SRC" "$REPO_ROOT/$LOCAL_COPY" <<'PY'
import os, pathlib, re, sys

dist, src, out = (pathlib.Path(a) for a in sys.argv[1:4])
html = (dist / "index.html").read_text()
rel = os.path.relpath(src.resolve(), out.parent.resolve())

SKIP = re.compile(r'^(?:[a-z][a-z0-9+.-]*:|//|#|\.\.?/)', re.I)

def repoint(m):
attr, val = m.group(1), m.group(2)
if SKIP.match(val):
return m.group(0)
# Only rewrite refs that actually resolve inside the source tree; anything
# else is left untouched rather than silently pointed somewhere wrong.
return f'{attr}="{rel}/{val}"' if (src / val).is_file() else m.group(0)

out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(re.sub(r'\b(src|href)="([^"]+)"', repoint, html))
print(f" assets re-pointed at {rel}/")
PY
fi

# ── manifest + summary ──────────────────────────────────────────────────────

say "build complete"
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ This project follows a Keep a Changelog-style format and uses version tags for r

## [Unreleased]

## [1.9.5] - 2026-08-12

### Changed

- **`build-cover-dist.sh` now emits the local cover snapshot itself**
(`LOCAL_COPY`, default `docs/cover.html`), removing the manual sync step that
produced two bugs in a row: a copy several versions behind, and a hero image
that never resolved. Hand-maintaining it could not work — the version badge is
injected at build time, so an edited duplicate is stale as soon as the version
moves, and because the copy lands outside `dist-cover/` its relative asset
paths dangle.
The new phase runs after the secret scan (so a snapshot is never written with
a leak the scan would have rejected) and re-points each asset reference at
`COVER_SRC`, computed relative to wherever the copy lands. Anchors, absolute
URLs, and references that do not resolve in the source tree are left alone
rather than silently rewritten. `LOCAL_COPY=""` skips the phase.

## [1.9.4] - 2026-08-12

### Fixed
Expand Down
8 changes: 4 additions & 4 deletions docs/cover.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- repo:8feed7b built:2026-08-13T03:41:41Z -->
<!-- repo:0153e21 built:2026-08-13T03:48:06Z -->
<!DOCTYPE html>
<html lang="en">
<head>
Expand Down Expand Up @@ -166,14 +166,14 @@

<section class="hero">
<div class="wrap">
<span class="badge">v1.9.4</span>
<span class="badge">v1.9.5</span>
<h1>actop<span>.</span></h1>
<p class="tagline">
Watch your Apple Silicon Mac the way it actually works — <strong>sudoless</strong>,
in-process, for M1–M4.
</p>
<div class="demo">
<img src="../images/actop-demo.gif" alt="actop live during a llama.cpp inference run: E-CPU/P-CPU/GPU/ANE utilization, per-core frequency, memory bandwidth, and power charts on Apple Silicon">
<img src="../cover/actop-demo.gif" alt="actop live during a llama.cpp inference run: E-CPU/P-CPU/GPU/ANE utilization, per-core frequency, memory bandwidth, and power charts on Apple Silicon">
<div class="caption">Live under a local llama.cpp run — the stack layout with braille then block sparklines, then the process panel with its watt-attributed PWR column.</div>
</div>
</div>
Expand Down Expand Up @@ -275,7 +275,7 @@ <h2>actop — Apple <span style="color: var(--accent);">C</span>hip top</h2>

<footer>
<div class="wrap">
<p>actop v1.9.4 · an independent project inspired by <a href="https://github.com/tlkh/asitop">asitop</a> · MIT licensed</p>
<p>actop v1.9.5 · an independent project inspired by <a href="https://github.com/tlkh/asitop">asitop</a> · MIT licensed</p>
</div>
</footer>

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "actop"
version = "1.9.4"
version = "1.9.5"
description = "Apple Silicon (M1–M4) power, GPU, ANE & memory-bandwidth monitor — sudoless TUI + Python API for profiling local LLM / MLX / CoreML inference"
readme = "README.md"
license = { text = "MIT" }
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.