본문으로 건너뛰기
cccskills
무료GitHub에 공개

moonbase

Optional Moonbase license-activation integration for Pulp — load-bearing compile settings, OpenSSL-at-configure caveat, the moonbase-pulp User-Agent contract, audio-thread gating + click-free fade, async start/pump, the interactive native (no-WebView) activation editor (frame-tick polling + the don't-rebuild-mid-event trap), loadable plugin/standalone formats, and headless screenshots.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md10.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Moonbase Skill

Use this when adding, building, or testing license activation / copy protection in a Pulp plugin or app with Moonbase, or when working under examples/moonbase-activation/.

Moonbase is a hosted licensing service. moonbase-cpp is a header-only, MIT-licensed C++17 client. Pulp consumes it via FetchContent (target moonbase::licensing) — no fork, no vendoring. Pulp owns only a registry entry, docs, this skill, and the reference example; upstream owns the SDK.

Load-bearing build settings (lead with these)

pulp add moonbase resolves the dependency and the link target, but it does not carry the two cache settings below. Set them before the dependency is made available:

set(MOONBASE_BUILD_TESTS    OFF CACHE BOOL "" FORCE)
set(MOONBASE_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(MOONBASE_USE_CURL       OFF CACHE BOOL "" FORCE)  # supply your own transport

target_link_libraries(MyPlugin PRIVATE moonbase::licensing)

MOONBASE_USE_CURL=OFF makes the upstream INTERFACE target define MOONBASE_DISABLE_CURL_TRANSPORT for you and drops libcurl. Inject a transport instead — the example supplies one over Pulp's cpp-httplib/mbedTLS stack.

The example places its license cache under ContentRegistry::platform_data_root(), which lives in pulp::content. No format target links pulp-content, so every target that compiles moonbase_activation_plugin.hpp must link it explicitly: each MoonbaseActivation_<fmt>, the screenshot generator and the test. Without it they fail with an undefined ContentRegistry::platform_data_root(). The example is OFF by default (PULP_BUILD_MOONBASE_EXAMPLE), so a normal build never surfaces this; configure with it ON after changing anything it links.

OpenSSL bolt-on (known upstream caveat)

Moonbase documents OpenSSL as a system requirement (its README expects OpenSSL::SSL/OpenSSL::Crypto findable on the system), and v3.3.0's CMake runs find_package(OpenSSL REQUIRED) and links it unconditionally, with no MOONBASE_CRYPTO_NATIVE CMake wiring. So OpenSSL must be present at configure time, and v1 simply uses the OpenSSL crypto backend (required + linked anyway) — the simplest, no-extra-wiring path. This is upstream's intended design, not a blocker and not a reason to fork. The example's CMake auto-discovers OpenSSL; per platform:

  • macOS: brew install openssl@3 (/opt/homebrew/opt/openssl@3 on Apple silicon); pass -DOPENSSL_ROOT_DIR=$(brew --prefix openssl@3) if needed.
  • Linux: apt install libssl-dev (or distro equivalent).
  • Windows: vcpkg (vcpkg install openssl) or a system package, discoverable via the toolchain / OPENSSL_ROOT_DIR.

OS-native crypto is optional, not v1's default. MOONBASE_CRYPTO_NATIVE is a preprocessor macro (define it on the consuming target and link the platform crypto libraries) that switches RS256 to Security.framework / CNG / system libcrypto. Since OpenSSL is a documented Moonbase requirement and is linked regardless, native crypto does not let you drop OpenSSL — so it buys little here. The example uses the OpenSSL backend; don't bother with native for v1.

moonbase-pulp User-Agent contract

Set Moonbase's client_info so Moonbase can attribute Pulp-driven traffic:

options.client_info = "moonbase-pulp/<version> (GenerousCorp Pulp; <OS>)";

It is appended after moonbase-cpp/<ver> in the HTTP User-Agent:

User-Agent: moonbase-cpp/3.3.0 moonbase-pulp/1.0.0 (GenerousCorp Pulp; macOS)

The moonbase-pulp token mirrors Moonbase's moonbase-juce convention, so their client segmentation attributes Pulp traffic with no work on their side. The example wires it through a single named constant; document it so even a hand-rolled integration sets it. Recommend it, don't silently force it — it is the developer's HTTP client and field.

Audio-thread gating rule

The one hard real-time rule. The audio thread reads a single atomic; everything else runs off-thread:

// process() — audio thread, lock-free:
if (!licensed.load(std::memory_order_relaxed)) {
    buffer.clear();   // or bypass / reduced functionality
    return;
}

All Moonbase calls are non-realtime (rt_safe: false). Never call Moonbase, allocate, or block from process(). A non-audio controller owns network, storage, and revalidation and publishes only the std::atomic<bool> licensed.

UI convention

  • Native by default, no WebView. The activation UI renders through Pulp's view/canvas stack. Online activation opens the system browser and the editor polls from the native controller (matching Moonbase's own reference flow). An embedded WebView is an optional later mode, not the default.
  • Theme tokens, not a Moonbase palette. Build the panel from pulp::view::Theme tokens so it inherits the host plugin's look. Moonbase supplies licensing behavior, not the editor's visual identity.
  • Two surfaces, one layout. build_activation_view() is a STATIC panel for a const controller (tests + the headless screenshot tool); ActivationPanel is the INTERACTIVE editor whose button drives the controller and which rebuilds on screen change. Both share the detail::lay_out_panel helpers, so the rich license-details rendering (name/email/product/type/expiry/seats) stays in one place.

Editor wiring (and the one reentrancy trap)

The live editor drives the controller from the view's frame clock (view.frame_clock()->subscribe([](float dt){...})): each tick calls controller.pump() (applies background revalidation), poll_once() ~1 s while in BrowserWait, and ActivationPanel::refresh_if_changed() to rebuild when the screen advances. Return false from the subscriber once the editor closes to auto-unsubscribe.

Never rebuild the view tree from inside a child's event handler. The action button's on_click must NOT call rebuild() — that destroys the very button whose click is still being dispatched (a use-after-free → SIGSEGV). Instead the handler only invokes the controller action + request_repaint(); the screen changed, so the next frame tick's refresh_if_changed() rebuilds safely once the event has unwound. This is why the action is deferred, not immediate.

Non-blocking startup (start_async / pump)

start_async() applies any stored license SYNCHRONOUSLY (the editor opens unlocked with no network wait) and re-validates online on a ONE-SHOT background thread. The worker only writes a mutex-guarded result slot + an atomic ready flag; screen_/license_ are touched solely on the UI thread (start_async/pump), so there is no data race on UI state and the audio thread still only reads licensed(). The controller joins the worker in its destructor. This is the HALO-style "synchronous-local-then-async-online" pattern — do not turn it into a continuous background poller (that reintroduces the UI-state race).

Click-free gate

Gate audio through a pulp::signal::SmoothedValue<float> (12 ms ramp set in prepare()), not a hard mute: gate_.set_target(licensed ? 1 : 0) then multiply each frame by gate_.next(). Before prepare() the ramp is one sample (an instant switch), so a unit test that never prepares still sees hard gating.

Loadable formats + screenshots

pulp_add_plugin(MoonbaseActivation FORMATS CLAP Standalone ...) builds a real loadable plugin + app; VST3/AU are appended when their developer-supplied SDKs are present. Each format target must also link moonbase::licensing + pulp-cpp-httplib (loop over MoonbaseActivation_<FMT>). The moonbase-activation-screenshots tool renders each screen headlessly via render_to_file(..., ScreenshotBackend::skia) — faithful text needs Skia in the build.

Controller scope

Keep the Pulp controller a thin router over upstream semantics. It owns UI state, background scheduling, generation-guarding of its own async callbacks, and the audio-thread atomic. It does not re-implement Moonbase's cross-process store locking, online-validation grace handling, or stale-write protection — lean on upstream's validate_token_online and file_license_store as-is.

Validate before shipping

  • Registry: python3 tools/packages/validate_registry.py --check-licenses — the moonbase entry is clean (license MIT, FetchContent, target moonbase::licensing).
  • Deps: python3 tools/deps/audit.py --strict — Moonbase must show DEPENDENCIES.md=yes NOTICE.md=yes licensing.md=yes.
  • Transport test: assert the moonbase-pulp token actually appears on the wire (method/URL/headers/body round-trip against a local server).
  • Gating test: with licensed=false, process() fades to silence; flipped to true, audio fades back to pass-through (assert the ramp is monotonic + settles, not just the steady state).
  • Interactive test: simulate_click the action button → controller advances (e.g. Welcome → BrowserWait) → refresh_if_changed() rebuilds; assert no WebView node after interaction.
  • Async test: start_async() with a stored license sets licensed() + the Details screen immediately; pump() in a loop never drops the license.
  • UI proof: render the activation screens through the Pulp view tree (Skia); assert no WebView node on the default path.
  • Loadable build: MoonbaseActivation_CLAP / _Standalone link and produce bundles; the screenshot tool writes faithful PNGs.
  • No live network in CI — live activation stays a manual local check.

Pointers

  • Reference plugin: examples/moonbase-activation/
  • Developer guide: docs/guides/copyright-protection.md
  • Registry entry: tools/packages/registry.json (moonbase)
  • Upstream: https://github.com/Moonbase-sh/moonbase-cpp (pinned v3.3.0)

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

aax

무료

Optional AAX support for Pulp, including developer-supplied Avid SDK setup, CMake enablement, DigiShell/AAX Validator workflows, and local AAX builds on macOS or Windows.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

Configure, implement, and test Pulp's optional desktop Ableton Link tempo-sync adapter while preserving the developer-supplied SDK, licensing, realtime, latency-compensation, and no-install boundaries.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

Maintain Pulp's installed design-time agent capability manifest and public-surface ledger. Use when adding, removing, renaming, or materially changing public audio, MIDI, signal, timebase, or sequence APIs; registering a new algorithm for generators; changing capability support or deprecation state; or repairing agent-capabilities freshness, schema, fingerprint, tombstone, or installed-SDK tests.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

android

무료

Android platform development for Pulp — NDK cross-compilation, Oboe audio, Dawn/Skia GPU rendering, JNI bridge, touch interaction, emulator workflows, and end-to-end smoke validation. Covers build, deploy, debug, and the gotchas discovered during bringup.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

ara

무료

Optional ARA support for Pulp, including developer-supplied ARA SDK setup, CMake enablement, adapter companion APIs, validation, and ARA-aware plugin implementation guidance.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

The measurement surface for ALL Pulp DSP and audio-pipeline work — read it BEFORE writing or gating DSP, not only when something already sounds wrong. Covers the C++ harness (signal generators, metrics, assertions, RenderScenario, contracts), the offline Audio Doctor (magnitude/frequency response, THD/THD+N, phase/group delay), and their Python sibling the Audio Quality Lab (tools/audio/quality-lab — null residual + alignment, LTAS log-spectral distance, spectral flux/centroid, HNR, Theil-Sen drift slope, Kaiser-sinc resampling, license-guarded corpus, regression-net ratchet). TRIGGER on AUTHORING work — "build/design an oscillator/filter/synth/effect", "add a DSP module", "what should the acceptance gate be", "how do I measure aliasing / anti-aliasing / alias floor", "null against a reference", "is this DSP correct", "choose a tolerance", "golden/regression corpus for audio", "measure drift or jitter", "A/B two renders" — AND on DEBUGGING work — "is there sound / no audio / I hear nothing", "does this filter/compressor/synth/delay produce the right signal", "prove the DSP / prove the contract", "measure the frequency response", "what's the THD / is it distorting", "what's the group delay / phase response / measured latency", "magnitude response curve", "render a test tone and assert", "audio regression", "64-frame works but 128 is silent", "sample-rate change pitch-shifted it", "describe what's in this buffer", "audio doctor", "compare before/after a DSP refactor". Reach for this BEFORE hand-rolling any FFT, null test, alias measurement, pitch tracker, or golden-render script — most of it already exists in one of the two lanes. Test/tool layer over HeadlessHost — deterministic, no audio device, no speakers. Off the realtime thread entirely.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 21일 업데이트

Generous-Corp의 스킬 모두 보기

이 스킬의 문제 신고