Skip to content

Tags: streamloop/streamkit

Tags

v0.6.0

Toggle v0.6.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
ci: isolate Docker image builders (streamer45#683)

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-servo-v0.2.4

Toggle plugin-servo-v0.2.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(plugins): servo host logging, bounded reply waits, first-frame in…

…strumentation (streamer45#668)

* fix(plugins): route servo shared-thread logs to host, bound reply waits, add first-frame instrumentation

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): reset first-render stopwatch on viewport resize and gate first-frame log on page_painted

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): gate frame readback on page_painted so deferred navigations emit transparent frames

Signed-off-by: streamkit-devin <[email protected]>

* chore(marketplace): regenerate official plugins metadata for servo 0.2.4

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-servo-v0.2.2

Toggle plugin-servo-v0.2.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(plugins): hold servo frame emission until initial page load (stre…

…amer45#658)

* fix(plugins): hold servo frame emission until initial page load

Captures previously started encoding immediately while the page was
still loading, producing several seconds of white/blank lead-in frames
(duration depending on site load time). The servo thread now reports
load+paint state with each frame and the node holds the first emitted
frame until the page is ready, capped by load_timeout_secs (previously
a documented no-op).

Signed-off-by: streamkit-devin <[email protected]>

* chore(plugins): bump servo plugin to 0.2.2

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): re-arm paint gate on deferred auth navigation

Also report poisoned instances as loaded so the first-frame gate does
not wait out the full load timeout on a cached fallback, and document
the load_timeout_secs / native_call_timeout_secs interaction.

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-servo-v0.2.1

Toggle plugin-servo-v0.2.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(examples): add web-capture gateway (streamer45#631)

* feat(examples): add web-capture gateway (clip/cast.streamkit.dev)

A thin Go gateway, mirroring examples/speech-gateway, that renders any web
page to video via the Servo plugin: clip.* returns a finite MP4 (oneshot),
cast.* serves a live WebM stream (dynamic session). The target URL is the
verbatim path suffix, with an optional comma-separated options segment
(dur=, vp=) and strong 720p30 defaults.

Worth a reviewer's attention:
- cast owns session lifetime (the engine does not auto-stop a pipeline when
  its MSE viewers disconnect): one shared session per URL+viewport, viewer
  refcount, idle + max-lifetime reaper, and graceful-shutdown teardown. The
  MSE proxy closes the upstream body on client disconnect so a read parked
  between frames can't keep the viewer count pinned.
- SSRF guard (public/URL-only): blocks loopback/private/link-local/CGNAT/
  cloud-metadata targets.
- Encoders are swappable profiles, software by default (runs GPU-free),
  hardware opt-in via --clip-encoder/--cast-encoder.
- Prometheus metrics incl. active sessions/viewers and reap counters.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* fix(web-capture): harden SSRF, session lifetime, and clip concurrency

Addresses code-review findings on the gateway:

- SSRF guard: also block 0.0.0.0/8, 198.18.0.0/15, and the IPv4 embedded in
  NAT64 (64:ff9b::/96) and 6to4 (2002::/16) IPv6 addresses.
- cast sessions: create on a background context so a creator disconnecting
  mid-create no longer fails the other deduped viewers (and the create error
  can't masquerade as a viewer "client gave up"); cap viewers up front with a
  clean 503 instead of failing downstream at max_clients; drop the reconcile
  step that could abandon a live session on a transient list miss.
- clip: acquireClip now observes client disconnect (no unbounded queueing on a
  full slot channel), and clip length rounds to whole frames instead of
  truncating sub-second durations.
- proxyMSE reuses a single retry timer; collapse the two near-identical HTTP
  clients into one; document the upstream-status guard (it prevents a
  WriteHeader panic). Fix README idle-TTL default (30, not 45).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* refactor(web-capture): embed pipeline YAML from template files

Move the clip/cast pipeline skeletons out of Go string constants into
cmd/gateway/pipelines/*.yml.tmpl, embedded via go:embed — they now read as
standalone (commented) YAML that can be diffed and reviewed on their own.
Rendering is unchanged: the same placeholder substitution (URL still
strconv.Quote'd) and per-profile encoder-block injection. The small per-profile
encoder snippets stay in encoders.go since they're tied to the profile metadata.

Also tighten the cast tests to assert on the `frame_count:` param rather than
the bare word, so a comment mentioning it can't trip them.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* fix(web-capture): close shutdown/create race, proxy + log correctness

Second review pass on the gateway:

- shutdownAll no longer leaks a session whose creation is in flight at SIGTERM:
  it marks the manager closed and waits each session's ready channel so it has
  an id to DELETE; acquire rejects new requests once closed. Previously an
  id-less in-flight session was skipped and re-registered after the maps were
  cleared, so its backend pipeline was never torn down.
- streamCopy only logs a copy error when the client is still connected — a
  normal cast disconnect (ctx canceled / closed body) is no longer logged as an
  error, which otherwise floods the log on a busy instance.
- copyHeaders strips the full hop-by-hop set (Connection, Upgrade, TE, Trailer,
  Keep-Alive, Proxy-*), not just Content-Length/Transfer-Encoding.
- serveCast renders the cast YAML lazily, so deduped viewers of an already-
  running stream don't do throwaway render work.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* feat(web-capture): H.264/fMP4 cast for Safari/iOS; user-role token

Leverage two just-merged backend PRs (auth streamer45#634, fMP4 MSE streamer45#637):

- cast can now serve H.264 in fragmented MP4 via new h264-sw/h264-hw cast
  profiles — http::mse auto-detects fMP4 (streamer45#637), so a plain <video> plays the
  live stream in Safari/iOS. The cast muxer is chosen per profile now (WebM for
  VP9/AV1, fMP4 for H.264); VP9/WebM stays the default for crisp screen text on
  Chromium/Firefox.
- Docs: the gateway no longer needs an admin token — the built-in user role now
  allows transport::http::mse (streamer45#634), so a user-role token covers the whole
  pipeline. (The demo's token minting is updated separately.)

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* refactor(web-capture): single host, output as the first path segment

Serve both outputs from one host (web.streamkit.dev): the path is
/{clip|cast}/[options/]{url} — output first, then optional config, then the
target URL. detectMode now reads the mode from the path only (the subdomain
branch is dropped), so any host works. Usage page, README, and tests updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: streamer45 <[email protected]>

* regression test

* fix(servo,web-capture): stop cross-session pixel leak; land clip first fragment fast

Servo's SoftwareRenderingContext shares a surfman surface pool across
instances, and spin_event_loop leaves the last-painted instance's
context bound — so a freshly-opened clip/cast could read another,
unrelated session's pixels (a privacy leak on the public demo).

- Gate surface reads on first paint: until notify_new_frame_ready has
  fired for the current page, emit a transparent frame instead of
  reading a possibly-stale surface; re-arm the gate on URL change.
- Re-bind the instance's rendering context immediately before
  read_to_image (after spin_event_loop) so the read always captures
  this instance's surface, never a concurrent node's.
- Add an isolated integration test that drives two concurrent solid-
  colour data: pages and asserts neither leaks the other's pixels.
- web-capture: tune the OpenH264 GOP to ~1s (one IDR per fps frames)
  so the fragmented-MP4 clip flushes its first playable fragment fast.

Signed-off-by: streamkit-devin <[email protected]>

* fix(servo): re-arm first-paint gate on viewport resize

A resize via UpdateConfig reallocates the surfman surface, which is
pooled across instances and may hold another instance's pixels until
the resized page repaints. Re-arm the painted gate (as on URL change)
so handle_render emits transparent frames until the post-resize paint,
closing the same cross-session leak on the resize path.

Signed-off-by: streamkit-devin <[email protected]>

* feat(examples/web-capture): serve autoplay clip player page for browser parity

Browser visits to /clip/* (Accept: text/html) now get the same autoplay
HTML player page already served for /cast/*, instead of the browser's bare
native media viewer. The page's <video> re-requests the same URL with
Accept: */* and receives the raw progressive MP4, so CLI clients
(curl/ffmpeg) are unaffected. The HTML branch runs before clip-slot acquire,
so a browser visit does not consume render concurrency.

Generalizes castPageTemplate/writeCastPage into playerPageTemplate/
writePlayerPage(kind) shared by both handlers.

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins/servo): clear cached frame on URL change

The URL-change branch of handle_update_config re-armed the first-paint
gate but left state.last_good_frame holding the previous URL's frame. If
read_to_image returned None on a tick after the new page painted,
handle_render fell back to that stale frame. Null it on URL change,
mirroring the viewport-resize branch.

Signed-off-by: streamkit-devin <[email protected]>

* fix(examples/web-capture): clamp max-concurrency to >=1, fix option example

--max-concurrency 0 sized clipSem as an unbuffered channel, deadlocking
every clip render; clamp to a floor of 1 via clampConcurrency. Also fix
the optionsSegmentRe comment to use the real 'res=' key instead of the
non-existent 'vp='.

Signed-off-by: streamkit-devin <[email protected]>

* feat(transport::http::mse): add fMP4 support for H.264 casting

The node only detected WebM Cluster IDs to delimit the init segment and
GOPs, so an H.264 cast stream (fragmented MP4: ftyp+moov init, repeating
moof+mdat fragments) never flipped init_complete and zero bytes reached
clients. Browsers showed nothing for the h264-sw cast encoder the demo
pins.

Detect the container framing from the first packet (ftyp/styp box at
offset 4 => fMP4, else WebM) and drive a parallel fMP4 state machine that
mirrors the WebM init+GOP replay: buffer ftyp+moov as the init segment,
split off the first moof-led fragment, and replay init + latest fragment
to late-joiners. The WebM path is unchanged.

Adds unit tests for framing detection, MP4 box scanning (incl. 64-bit
largesize), init/fragment splitting, cross-packet init buffering, and
GOP buffer capping.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): close pipe reader if clip request build fails

If http.NewRequestWithContext fails in proxyOneshot, the multipart writer
goroutine parks forever on the io.Pipe whose reader is never consumed. Close
the reader on the error path so the worker unwinds. Addresses Devin Review.

Signed-off-by: streamkit-devin <[email protected]>

* chore(plugins/servo): bump version to 0.1.1

Release-ready bump covering the cross-session pixel-leak privacy fix and the
first-paint transparent-frame gate. Regenerates marketplace/official-plugins.json
via scripts/marketplace/generate_official_plugins.py.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): fail fast in proxyMSE when session reaped mid-retry

A post-teardown 404 from the MSE upstream is indistinguishable by status
from a pre-ready 404, so the readiness loop spun the full mseReadyTimeout
and returned a misleading 502 when a session was reaped (idle/max-lifetime)
just as a deduped late viewer connected. Check session liveness in the loop
and return 503 immediately when the session is gone.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): block IPv4-compatible IPv6 and local-use NAT64 in SSRF guard

::a.b.c.d (IPv4-compatible) bypassed blockedV4 because To4() returns nil,
and the RFC 8215 local-use NAT64 prefix (64:ff9b:1::/48) was not matched by
embeddedV4, so ::169.254.169.254 and 64:ff9b:1::a9fe:a9fe reached the
metadata IP. Extend embeddedV4 to extract the embedded v4 from both forms
and re-screen it; add regression cases for the two bypasses.

Signed-off-by: streamkit-devin <[email protected]>

* perf(web-capture): defer target DNS lookup off the player-page path

handleCapture ran the full validateTarget (up to a 5s DNS lookup) before the
acceptsHTML short-circuit, so a browser address-bar visit paid the lookup just
to render the static autoplay page. Split out parseTargetURL (scheme +
literal-IP screen, no DNS) for the cheap fail-fast path and defer the hostname
resolution into serveClip/serveCast after the player page is served. Also drop
the dead dur<=0 re-defaulting in serveClip (opts.dur is always >0).

Signed-off-by: streamkit-devin <[email protected]>

* refactor(servo): dedupe transparent-frame paths and surface make_current errors

Extract a transparent_frame(w,h) helper and route the unpainted, panic-fallback,
and read_to_image-miss paths through it, collapsing three copies of the buffer
build. Move the painted-surface read into read_painted_frame and stop discarding
the make_current() Result before read_to_image — a bind failure means the frame
may not be this instance's surface, so log it instead of silently risking the
cross-session leak the bind is meant to prevent.

Signed-off-by: streamkit-devin <[email protected]>

* refactor(web-capture): dedupe gateway auth/maxViewers state and strip Connection-listed headers

- Drop gateway.authToken/authReq; route auth through the single skitClient.auth.
- Drop gateway.maxViewers; read from the session manager so the two can't drift.
- copyHeaders now also strips headers named in the Connection header (RFC 7230 §6.1).

Signed-off-by: streamkit-devin <[email protected]>

* chore(deps): bump anyhow + wasmtime-wasi and ignore ttf-parser unmaintained advisory

Resolves the cargo-deny advisory failures from newly published RUSTSEC notices:
- anyhow 1.0.102 -> 1.0.103 (RUSTSEC-2026-0190, downcast_mut unsoundness)
- wasmtime-wasi 46.0.0 -> 46.0.1 (RUSTSEC-2026-0188, WASI FilePerms bypass)
- ignore RUSTSEC-2026-0192 (ttf-parser unmaintained via fontdue; no safe
  upgrade, tracked in streamer45#642), matching the existing unmaintained-advisory ignores.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): reject sessions whose create finishes after shutdown

A create in flight when shutdownAll ran would re-register its id in the
fresh byID map and hand the caller a session that shutdownAll was about
to destroy. Now acquire re-checks closed after the create resolves and
returns errShuttingDown; shutdownAll still tears the pipeline down.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): derive MSE Content-Type fallback from the cast encoder profile

Store encoder content types as plain MIME strings (YAML-quoted at
template render time via strconv.Quote) so proxyMSE can reuse the
active cast profile's type instead of a hardcoded video/webm that would
mislabel H.264/fMP4 streams if the upstream header were ever missing.

Also bound the stream client's wait for upstream response headers so a
hung backend can't pin a viewer request indefinitely.

Signed-off-by: streamkit-devin <[email protected]>

* fix(web-capture): clamp max-sessions/max-viewers and drop unused authToken field

A max-sessions or max-viewers value < 1 would silently reject every
cast; floor them at 1 with a log line, like max-concurrency.

Signed-off-by: streamkit-devin <[email protected]>

* chore(servo): drop redundant uuid dev-dependency

Integration tests already see the identical uuid entry from
[dependencies].

Signed-off-by: streamkit-devin <[email protected]>

* chore(deps): ignore quick-xml RUSTSEC-2026-0194/0195 advisories via opendal

No upgrade path exists: opendal 0.57 (latest) pins quick-xml 0.39, while the
fixes land in quick-xml >= 0.41. Exposure is limited to XML responses from
the operator-configured S3 endpoint. Removal tracked in streamer45#647.

Signed-off-by: streamkit-devin <[email protected]>

* chore(deps): update crossbeam-epoch to 0.9.20 for RUSTSEC-2026-0204

Signed-off-by: streamkit-devin <[email protected]>

* clarify

---------

Signed-off-by: streamer45 <[email protected]>
Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-servo-v0.2.0

Toggle plugin-servo-v0.2.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(plugins): bump servo to 0.4.0 and add auth config for private pa…

…ges (streamer45#630)

* feat(plugins): bump servo to 0.3.0 and add auth config for private pages

Upgrade the native Servo web-renderer plugin from servo 0.1 to 0.3.0 and wire a new optional `auth` config through ServoConfig to WebView creation.

- Custom request headers / bearer token attached to the initial navigation via the 0.3.0 UrlRequest/load_request API.
- HTTP Basic/Digest answered non-interactively via the WebViewDelegate request_authentication hook.
- Custom User-Agent applied to the process-global servo Preferences (affects all servo nodes).

Auth is init-time only (not hot-swapped on UpdateConfig). Credentials are never logged and userinfo is stripped from logged URLs.

Signed-off-by: streamkit-devin <[email protected]>

* chore(plugins): regenerate official-plugins.json for servo 0.2.0

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): re-apply servo auth headers on runtime URL changes

handle_update_config navigated via webview.load(), which dropped the configured custom/bearer request headers when the tunable url parameter changed at runtime, silently breaking header auth on subsequent private pages (basic auth, bound to the delegate, kept working). Route both initial and runtime navigations through a shared navigate_with_auth helper so header/bearer auth stays consistent with basic auth.

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): redact URL credentials in servo validation/creation errors

Signed-off-by: streamkit-devin <[email protected]>

* ci: retrigger servo lint after runner out-of-disk failure

Signed-off-by: streamkit-devin <[email protected]>

* feat(plugins): bump servo to 0.4.0

servo-script 0.4.0 pins p256/p384/p521 =0.14.0-rc.14, which do not
build against the latest primeorder 0.14.0; the lockfile pins
primeorder 0.14.0-rc.14 to keep the graph consistent.

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): load initial servo URL via WebViewBuilder to avoid dropped navigation

Signed-off-by: streamkit-devin <[email protected]>

* fix(plugins): defer header-carrying navigation to the render loop

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-slint-v0.5.0

Toggle plugin-slint-v0.5.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based d…

…emo image (streamer45#638)

* feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based demo image

Add optional per-plugin CUDA bundle variants alongside the canonical CPU
bundle, end-to-end across schema, install client, release pipeline, and
the CPU demo image.

- marketplace.rs: add backward-compatible variants[] to manifests
  (empty => byte-identical to pre-variant CPU manifests).
- marketplace_installer.rs: resolve bundle by explicit accelerator or
  CUDA auto-detect (libcuda probe), falling back to the CPU bundle.
- build_registry.py / verify_bundles.py: --accelerator passes layer a
  cuda variant onto the published CPU manifest (append-only, immutable);
  CUDA NEEDED/RUNPATH deps allowlisted for cuda bundles only.
- CI: build-marketplace-cuda job on the self-hosted Ada GPU runner builds
  + publishes <id>-<ver>-cuda-bundle.tar.zst to the per-plugin release.
- Dockerfile.demo: fetch sha256-pinned prebuilt CPU marketplace bundles
  instead of rebuilding 11 plugins from source; drop the from-source
  sherpa-onnx copy (bundles vendor their own libs) and the torch-based
  Helsinki conversion (pull pre-converted model tarballs).

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): don't block registry publish on skipped CUDA build

publish-registry depends on build-marketplace-cuda, which is skipped when
build_cuda=false. A skipped dependency fails the implicit success() gate,
so CPU registry publishing was silently skipped too. Gate publish-registry
on the CPU build succeeding and the CUDA build not failing.

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): pass signing key to CUDA registry build

build_registry.py requires --signing-key, but the CUDA registry variant
step omitted it, so argparse would abort the GPU registry build (and, via
the publish-registry guard, block CPU publishing too).

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): harden GPU variant pipeline and detect accelerator switch

Addresses review findings on the marketplace GPU bundle work:

- Make build-marketplace-cuda best-effort (continue-on-error) so a failed
  GPU job no longer blocks CPU per-plugin releases or registry publishing;
  simplify the publish-registry guard to gate solely on the CPU build.
- Guard the empty Bash array expansion in build_official_plugins_cuda.sh so
  feature-less plugins build under set -u on Bash < 4.4.
- Embed manifest.json in CUDA variant bundles for parity with CPU bundles.
- Record the activated accelerator in an installed bundle and return a clear
  'already installed as <variant>' error instead of a silent no-op when a
  request would switch the variant for an already-installed version.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): carry plugin asset types into bundles + harden CUDA variant build

Asset types (e.g. Slint's) declared in plugin.yml were dropped by
build_manifest, so manifest.json never carried them. The server only
learns asset types from a plugin.yml beside the .so, so both raw-extraction
consumers (the demo image) and real marketplace installs lost the type.

- build_manifest now includes a non-empty assets block (omitted when empty,
  keeping asset-less manifests byte-identical for the append-only check).
- build_bundle embeds a plugin.yml beside the entrypoint so bundles are
  self-describing, matching what the installer writes post-download.
- Bump slint 0.4.0 -> 0.5.0 so the corrected, assets-bearing manifest can be
  published under the append-only registry; inject the source plugin.yml into
  the demo's pinned (pre-self-describing) slint bundle in the interim.
- build_official_plugins_cuda.sh fails loudly when a cuda-declared plugin has
  neither a cuda Cargo feature nor sherpa linkage (was silently packaging a
  CPU .so as the cuda variant).
- CUDA variant pass verifies the existing manifest signature before re-signing,
  matching the CPU reuse path.
- Mirror the assets field in check_registry_versions.py.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): re-key bundle installs by accelerator and address review findings

Key install dirs by id+version+accelerator so CPU and CUDA variants of the
same version coexist and switching never silently no-ops; removes the
.accelerator marker and its fail-open path. resolve_accelerator is probed once
and threaded through download_bundle. ActivePluginRecord now tracks the
activated accelerator.

Build/registry: extract shared manifest_builder (build_manifest + SHERPA libs)
so the builder and append-only guard cannot drift; normalize accelerator case
in reuse/dedup; drop the dead variants fallback. Whisper bundle build pins
SOURCE_DATE_EPOCH + -march=x86-64 for portable ggml. Demo pins
ggml-tiny-q5_1.bin sha256 and injects a version-matched slint plugin.yml.

Signed-off-by: streamkit-devin <[email protected]>

* chore(ci): retrigger checks after apt mirror flake in servo lint

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): apply whisper portability flags to CUDA build and guard variant manifests

Signed-off-by: streamkit-devin <[email protected]>

* test(server): exercise accelerator-keyed bundle removal on uninstall

Signed-off-by: streamkit-devin <[email protected]>

* feat(ui): surface accelerator variants in marketplace and installed plugins

Expose the active accelerator on PluginSummary (from active records on
restart and from the installer on fresh installs), add an accelerator
selector (auto-detect/cpu/cuda) to the marketplace details pane wired to
InstallPluginRequest.accelerator, and show the active variant in the
installed plugins list.

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-parakeet-v0.3.1

Toggle plugin-parakeet-v0.3.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based d…

…emo image (streamer45#638)

* feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based demo image

Add optional per-plugin CUDA bundle variants alongside the canonical CPU
bundle, end-to-end across schema, install client, release pipeline, and
the CPU demo image.

- marketplace.rs: add backward-compatible variants[] to manifests
  (empty => byte-identical to pre-variant CPU manifests).
- marketplace_installer.rs: resolve bundle by explicit accelerator or
  CUDA auto-detect (libcuda probe), falling back to the CPU bundle.
- build_registry.py / verify_bundles.py: --accelerator passes layer a
  cuda variant onto the published CPU manifest (append-only, immutable);
  CUDA NEEDED/RUNPATH deps allowlisted for cuda bundles only.
- CI: build-marketplace-cuda job on the self-hosted Ada GPU runner builds
  + publishes <id>-<ver>-cuda-bundle.tar.zst to the per-plugin release.
- Dockerfile.demo: fetch sha256-pinned prebuilt CPU marketplace bundles
  instead of rebuilding 11 plugins from source; drop the from-source
  sherpa-onnx copy (bundles vendor their own libs) and the torch-based
  Helsinki conversion (pull pre-converted model tarballs).

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): don't block registry publish on skipped CUDA build

publish-registry depends on build-marketplace-cuda, which is skipped when
build_cuda=false. A skipped dependency fails the implicit success() gate,
so CPU registry publishing was silently skipped too. Gate publish-registry
on the CPU build succeeding and the CUDA build not failing.

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): pass signing key to CUDA registry build

build_registry.py requires --signing-key, but the CUDA registry variant
step omitted it, so argparse would abort the GPU registry build (and, via
the publish-registry guard, block CPU publishing too).

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): harden GPU variant pipeline and detect accelerator switch

Addresses review findings on the marketplace GPU bundle work:

- Make build-marketplace-cuda best-effort (continue-on-error) so a failed
  GPU job no longer blocks CPU per-plugin releases or registry publishing;
  simplify the publish-registry guard to gate solely on the CPU build.
- Guard the empty Bash array expansion in build_official_plugins_cuda.sh so
  feature-less plugins build under set -u on Bash < 4.4.
- Embed manifest.json in CUDA variant bundles for parity with CPU bundles.
- Record the activated accelerator in an installed bundle and return a clear
  'already installed as <variant>' error instead of a silent no-op when a
  request would switch the variant for an already-installed version.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): carry plugin asset types into bundles + harden CUDA variant build

Asset types (e.g. Slint's) declared in plugin.yml were dropped by
build_manifest, so manifest.json never carried them. The server only
learns asset types from a plugin.yml beside the .so, so both raw-extraction
consumers (the demo image) and real marketplace installs lost the type.

- build_manifest now includes a non-empty assets block (omitted when empty,
  keeping asset-less manifests byte-identical for the append-only check).
- build_bundle embeds a plugin.yml beside the entrypoint so bundles are
  self-describing, matching what the installer writes post-download.
- Bump slint 0.4.0 -> 0.5.0 so the corrected, assets-bearing manifest can be
  published under the append-only registry; inject the source plugin.yml into
  the demo's pinned (pre-self-describing) slint bundle in the interim.
- build_official_plugins_cuda.sh fails loudly when a cuda-declared plugin has
  neither a cuda Cargo feature nor sherpa linkage (was silently packaging a
  CPU .so as the cuda variant).
- CUDA variant pass verifies the existing manifest signature before re-signing,
  matching the CPU reuse path.
- Mirror the assets field in check_registry_versions.py.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): re-key bundle installs by accelerator and address review findings

Key install dirs by id+version+accelerator so CPU and CUDA variants of the
same version coexist and switching never silently no-ops; removes the
.accelerator marker and its fail-open path. resolve_accelerator is probed once
and threaded through download_bundle. ActivePluginRecord now tracks the
activated accelerator.

Build/registry: extract shared manifest_builder (build_manifest + SHERPA libs)
so the builder and append-only guard cannot drift; normalize accelerator case
in reuse/dedup; drop the dead variants fallback. Whisper bundle build pins
SOURCE_DATE_EPOCH + -march=x86-64 for portable ggml. Demo pins
ggml-tiny-q5_1.bin sha256 and injects a version-matched slint plugin.yml.

Signed-off-by: streamkit-devin <[email protected]>

* chore(ci): retrigger checks after apt mirror flake in servo lint

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): apply whisper portability flags to CUDA build and guard variant manifests

Signed-off-by: streamkit-devin <[email protected]>

* test(server): exercise accelerator-keyed bundle removal on uninstall

Signed-off-by: streamkit-devin <[email protected]>

* feat(ui): surface accelerator variants in marketplace and installed plugins

Expose the active accelerator on PluginSummary (from active records on
restart and from the installer on fresh installs), add an accelerator
selector (auto-detect/cpu/cuda) to the marketplace details pane wired to
InstallPluginRequest.accelerator, and show the active variant in the
installed plugins list.

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

plugin-nllb-v0.3.1

Toggle plugin-nllb-v0.3.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based d…

…emo image (streamer45#638)

* feat(marketplace): GPU (CUDA) plugin bundle variants + bundle-based demo image

Add optional per-plugin CUDA bundle variants alongside the canonical CPU
bundle, end-to-end across schema, install client, release pipeline, and
the CPU demo image.

- marketplace.rs: add backward-compatible variants[] to manifests
  (empty => byte-identical to pre-variant CPU manifests).
- marketplace_installer.rs: resolve bundle by explicit accelerator or
  CUDA auto-detect (libcuda probe), falling back to the CPU bundle.
- build_registry.py / verify_bundles.py: --accelerator passes layer a
  cuda variant onto the published CPU manifest (append-only, immutable);
  CUDA NEEDED/RUNPATH deps allowlisted for cuda bundles only.
- CI: build-marketplace-cuda job on the self-hosted Ada GPU runner builds
  + publishes <id>-<ver>-cuda-bundle.tar.zst to the per-plugin release.
- Dockerfile.demo: fetch sha256-pinned prebuilt CPU marketplace bundles
  instead of rebuilding 11 plugins from source; drop the from-source
  sherpa-onnx copy (bundles vendor their own libs) and the torch-based
  Helsinki conversion (pull pre-converted model tarballs).

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): don't block registry publish on skipped CUDA build

publish-registry depends on build-marketplace-cuda, which is skipped when
build_cuda=false. A skipped dependency fails the implicit success() gate,
so CPU registry publishing was silently skipped too. Gate publish-registry
on the CPU build succeeding and the CUDA build not failing.

Signed-off-by: streamkit-devin <[email protected]>

* ci(marketplace): pass signing key to CUDA registry build

build_registry.py requires --signing-key, but the CUDA registry variant
step omitted it, so argparse would abort the GPU registry build (and, via
the publish-registry guard, block CPU publishing too).

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): harden GPU variant pipeline and detect accelerator switch

Addresses review findings on the marketplace GPU bundle work:

- Make build-marketplace-cuda best-effort (continue-on-error) so a failed
  GPU job no longer blocks CPU per-plugin releases or registry publishing;
  simplify the publish-registry guard to gate solely on the CPU build.
- Guard the empty Bash array expansion in build_official_plugins_cuda.sh so
  feature-less plugins build under set -u on Bash < 4.4.
- Embed manifest.json in CUDA variant bundles for parity with CPU bundles.
- Record the activated accelerator in an installed bundle and return a clear
  'already installed as <variant>' error instead of a silent no-op when a
  request would switch the variant for an already-installed version.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): carry plugin asset types into bundles + harden CUDA variant build

Asset types (e.g. Slint's) declared in plugin.yml were dropped by
build_manifest, so manifest.json never carried them. The server only
learns asset types from a plugin.yml beside the .so, so both raw-extraction
consumers (the demo image) and real marketplace installs lost the type.

- build_manifest now includes a non-empty assets block (omitted when empty,
  keeping asset-less manifests byte-identical for the append-only check).
- build_bundle embeds a plugin.yml beside the entrypoint so bundles are
  self-describing, matching what the installer writes post-download.
- Bump slint 0.4.0 -> 0.5.0 so the corrected, assets-bearing manifest can be
  published under the append-only registry; inject the source plugin.yml into
  the demo's pinned (pre-self-describing) slint bundle in the interim.
- build_official_plugins_cuda.sh fails loudly when a cuda-declared plugin has
  neither a cuda Cargo feature nor sherpa linkage (was silently packaging a
  CPU .so as the cuda variant).
- CUDA variant pass verifies the existing manifest signature before re-signing,
  matching the CPU reuse path.
- Mirror the assets field in check_registry_versions.py.

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): re-key bundle installs by accelerator and address review findings

Key install dirs by id+version+accelerator so CPU and CUDA variants of the
same version coexist and switching never silently no-ops; removes the
.accelerator marker and its fail-open path. resolve_accelerator is probed once
and threaded through download_bundle. ActivePluginRecord now tracks the
activated accelerator.

Build/registry: extract shared manifest_builder (build_manifest + SHERPA libs)
so the builder and append-only guard cannot drift; normalize accelerator case
in reuse/dedup; drop the dead variants fallback. Whisper bundle build pins
SOURCE_DATE_EPOCH + -march=x86-64 for portable ggml. Demo pins
ggml-tiny-q5_1.bin sha256 and injects a version-matched slint plugin.yml.

Signed-off-by: streamkit-devin <[email protected]>

* chore(ci): retrigger checks after apt mirror flake in servo lint

Signed-off-by: streamkit-devin <[email protected]>

* fix(marketplace): apply whisper portability flags to CUDA build and guard variant manifests

Signed-off-by: streamkit-devin <[email protected]>

* test(server): exercise accelerator-keyed bundle removal on uninstall

Signed-off-by: streamkit-devin <[email protected]>

* feat(ui): surface accelerator variants in marketplace and installed plugins

Expose the active accelerator on PluginSummary (from active records on
restart and from the installer on fresh installs), add an accelerator
selector (auto-detect/cpu/cuda) to the marketplace details pane wired to
InstallPluginRequest.accelerator, and show the active variant in the
installed plugins list.

Signed-off-by: streamkit-devin <[email protected]>

---------

Signed-off-by: streamkit-devin <[email protected]>
Co-authored-by: streamkit-devin <[email protected]>

v0.5.0

Toggle v0.5.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: revert Parakeet 0.3.0 manifest to match signed content (streamer…

…45#422)

PR streamer45#378 manually added a `repository` field to the Parakeet 0.3.0
manifest in docs/public/registry without re-signing it. The minisig
was generated for the original manifest (without `repository`), so
signature verification fails with 'Minisign signature verification
failed'.

- Revert docs/public manifest to match dist/registry (signed) content
- Add verify_existing_signature() guard in build_registry.py to catch
  manifest-signature mismatches when reusing existing registry entries
- Add unit tests for the new guard function

Signed-off-by: StreamKit Devin <[email protected]>
Co-authored-by: StreamKit Devin <[email protected]>
Co-authored-by: Claudio Costa <[email protected]>

plugin-whisper-v0.3.0

Toggle plugin-whisper-v0.3.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(engine): replace fixed sleeps with polling in backpressure tests (s…

…treamer45#370)

The test_dynamic_connection_under_backpressure test used a fixed 100ms
sleep before asserting the pacer node reached Running state. On slow CI
runners the node lifecycle (Creating → Initializing → Running) takes
longer than 100ms, causing sporadic assertion failures.

Replace all fixed sleep + assert patterns across the three backpressure
tests with a wait_for_states polling helper (same pattern used in the
async_node_creation test suite). Each call polls get_node_states() every
20ms with a 5-second timeout, eliminating timing-dependent flakiness.

Signed-off-by: StreamKit Devin <[email protected]>
Co-authored-by: StreamKit Devin <[email protected]>
Co-authored-by: Claudio Costa <[email protected]>