Skip to content

Releases: 1fairyfox/random-ai-prompt

v2.60.3

Choose a tag to compare

@github-actions github-actions released this 03 Aug 04:39
3129f1d

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

Changelog — August 2026

Newest entry on top.

2026-08-02 — security (2.60.3) — remediate the OpenSSF Scorecard (6.7 → projected ~7.4)

Closed the compliance audit's headline finding (ship-contract Scorecard below the 7.0 floor) by
clearing the dominant lever — the Vulnerabilities check (was 0). Fixed everything fixable:
root + targets/web npm audit fix (→ 0 vulns each), and targets/mobile pinned postcss ^8.5.25

  • brace-expansion ^2.0.2 via overrides. Documented + filtered the genuine-no-fix advisories
    via osv-scanner.toml next to each manifest (the mechanism Scorecard's Vulnerabilities check honors):
    17 unmaintained Tauri-v2-Linux gtk3-rs/glib/proc-macro/unic Rust crates (confirmed no-fix by
    cargo audit) in targets/web-shell/, and 1 build-time-only Expo uuid advisory in targets/mobile/.
    Verified with the real tool — osv-scanner v2.4.0 reports "No issues found" — so the check moves
    0 → 10, lifting the score to ~7.4. npm test green (375 + 430 + 122). PATCH 2.60.2 → 2.60.3. The public
    api.securityscorecards.dev number refreshes on OSSF's weekly rescan. Report:
    ../fairyfox-reports/2026-08-02-scorecard-remediation.md.

2026-08-02 — docs/notes — fairyfox: first full standards compliance audit

Ran the first full compliance audit (the gap seeded in the 2026-08-02 adoption). Walked every
adopted standard's ## Verify and recorded a dated per-standard result in
../reference/adoption-manifest.md: 25/30 applicable standards
implemented
(34 rows − 4 N-A; 5 non-implemented), the rest honest dated gaps. Headline finding: the ship-contract's OpenSSF Scorecard
is 6.7, below the 7.0 floor
— verified against the live api.securityscorecards.dev (not the badge).
The dominant lever is Vulnerabilities = 0 (27 known, mostly RUSTSEC advisories in the Tauri/Rust
desktop deps); several other checks (Code-Review, Contributors, Branch-Protection) are structurally low
for a solo 0-approval repo. Also partial: supply-chain (releases signed but no provenance), docs-site
(chrome 2.2.1 → 2.3.0, browser-gated), docker (no Dockerfile yet), mandate-ledger (no ledger triggered).
Fixed in-pass: pruned 5 stale Dependabot branches → the remote carries only main/dev
(repo-hygiene clean). Also flags a date-accuracy correction: earlier artifacts in this effort were
mis-dated 2026-07-25 (hub-commit date); the real date is 2026-08-02. Report:
../fairyfox-reports/2026-08-02-compliance-audit.md.
No VERSION bump (notes/docs only).

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.60.3-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.60.3.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.60.3-docs.zip -- the generated documentation site.

What's Changed

  • docs: first full standards compliance audit by @1fairyfox in #65
  • Release v2.60.3 — Scorecard security remediation by @1fairyfox in #66

Full Changelog: v2.60.2...v2.60.3

v2.60.2

Choose a tag to compare

@github-actions github-actions released this 25 Jul 12:01
24f266b

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-25 — deps (2.60.2) — merge all four pending Dependabot groups (#56, #57, #59, #60)

Closed every open Dependabot PR during the release, verified against the project's own dev gate.
Dependabot regenerated the groups mid-release (#59/#60 superseded #56/#57 with newer targets), so all
four were folded into dev, superset-wins. Final merged state — engine group: compromise
14.15.1→14.16.0, @playwright/test 1.61.1→1.62.0, eslint 10.6.0→10.8.0, prettier
3.9.4→3.9.6, stylelint 17.14.0→17.14.1; github-actions group: action-version pins bumped
across all nine workflow files (ci, codeql, scorecard, sonar, pages, release,
netlify-deploy, branch-sync, visual-baselines) — e.g. actions/checkout v7.0.1,
actions/setup-node v7.0.0, actions/setup-java v5.6.0 — no code impact. Merged into dev with
--no-ff and verified locally with npm install + npm test green (the project's dev gate; CI
runs only on the main PR). PATCH bump 2.60.1 → 2.60.2.

2026-07-25 — docs/notes — fairyfox: adopt the hub 0.20.2 → 1.6.1 standards span

Ran the fairyfox adopting-updates flow against hub 1.6.1 (the mirror had been force-pushed and
renumbered from 0.20.x). Adopted the whole span under the standing adopt-standards-by-default grant:
seeded the project's first notes/reference/adoption-manifest.md (the 0.21.0 linchpin — a per-
standard record where copied-only ≠ adopted and no Standards adopted ✅ is written without a
backing row); added four new-standard notes — checklists-are-contracts, mandate-ledger, docker,
readme; folded the material changes into planning (phase-by-default), engineering-quality (the
ship contract — Scorecard ≥ 7.0 floor, tech-debt removal, PR triage), git-workflow (the pre-release
manifest gate), coins (base counter mandatory), and compliance (matrix rows); and wired
checklists-are-contracts / mandate-ledger / the manifest / phase-by-default into CLAUDE.md Default
Workflow step 0. The README was brought to the new readme standard: a worded 📖 Documentation
link near the top, an organized Get it section (Try it live / Download / Source), and a mesh
footer
; its badge block already carried all 20 canonical badges in order (adopted as a filing act).
Browser-gated docs-site visual work — the chrome bump 2.2.1 → 2.3.0 plus the 1.4.0 subnav / on-
site Notes / coins-presence requirements — is deferred as a named tracked gap in the manifest, per
the runbook's "phase a mixed adoption." Notes/docs + README only — no VERSION bump. Full account:
fairyfox-reports/2026-07-25-adopting-updates.md.

2026-07-19 — docs-site — fairyfox: add the coins counter to the docs chrome

The docs-site shared chrome gained the coins reading-engagement counter (a button beside the reader
"Aa"), correcting an earlier miscall that filed coins as out-of-scope — it ships as part of the chrome
this node already wears, and the docs site is same-origin under fairyfox.io/<key>/, so it shares the
hub wallet. Verified the rest of the chrome is already current at bundle 2.2.1 (reader constants + nav
match the master); coins was the sole gap. assets/docs-theme/modules/coins.js is the master coins.js
vendored verbatim (the earning engine must not be reimplemented), injected after initReader() so
its button sits left of "Aa"; theme/coins.css carries the button/panel/pop/read-time styles on the
project tokens; notes/reference/coins.md + a compliance row document it. Same-origin with the hub, so
the hub /legal/coins/ page covers the fairyfox:coins:a disclosure and no project legal page changes.
Notes/docs-theme only — no VERSION bump. Verified: npm run docs, check:docs, lint/format:check.

2026-07-19 — docs — fairyfox: adopt six new mesh standards as reference notes

A fairyfox system update check refreshed the hub mirror to 0.20.2 and found six standards that
postdate this node's last adoption — all already practiced here but with no first-class home in the
tree. Under the hub's standing adopt-standards-by-default authorization (owner-confirmed scope: adopt
all), added notes/reference/{engineering-quality,planning,research-capture,working-rhythm, self-hosted-assets,agent-tooling}.md, each mapping the hub canonical to how this project already
satisfies it (working-agreements, the Default Workflow, self-hosted fonts, PowerShell/file-tools,
notes-first). Wired in: a plan-before-execute step 0 in the CLAUDE.md Default Workflow, rows for
all six in the compliance audit matrix, and index/folder-map entries in
notes/README.md. Notes-only — no VERSION bump. Verification: check:docs (461 links), format:check,
smoke all green. Process reports: notes/fairyfox-reports/2026-07-19-{check-for-updates,adopting-updates}.md.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.60.2-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.60.2.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.60.2-docs.zip -- the generated documentation site.

What's Changed

Full Changelog: v2.60.1...v2.60.2

v2.60.1

Choose a tag to compare

@github-actions github-actions released this 13 Jul 03:51
fea69d4

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-13 — 2.60.1 — Security: the backend could be made to run arbitrary commands

CodeQL flagged it on the release PR and it was right. /api/image/open and /api/image/reveal built a
shell string around a request-derived path:

exec(`cmd /c start "" "${fp}"`);
exec(`explorer /select,"${fp}"`);

resolveOutputFile() blocks path traversal and nothing else, so an image in the output folder named
x" & calc & ".png closes the quote and everything after it runs. The ImageMagick convert/resize calls
had the same shape. Severity: critical (js/command-line-injection).
The fix is structural, not a better escape function — escaping is a losing game played on the attacker's
board. No shell: the program and its arguments are built separately (new
targets/web/backend/osCommands.js, pure and testable) and handed to execFile, which passes argv
straight to the OS. A quote inside a filename is then just a quote inside a filename. detectMagick
lost its shell too — nothing there needed one.
Three more from the same sweep, all real:

  • Prototype pollution (js/remote-property-injection, high): mergeSidecar merged a
    request-supplied patch key-by-key into a plain object, so {"__proto__": {…}} mutated
    Object.prototype for the whole process. Those keys are now dropped.
  • World-writable temp cache (js/insecure-temporary-file, high): the remote manifest was cached at a
    fully predictable path in os.tmpdir(), where any local account could pre-create or symlink it — and
    we'd write through it and then trust what we read back. Moved into the app's own directory, mode 0600.
  • Check-then-use races (js/file-system-race, high ×3): existsSync + read/write/unlink. Replaced
    with do-it-and-handle-ENOENT/EEXIST — the check was always a lie about the future anyway.
    Regression-tested (tests/regression/commandInjection.test.js, 5), and the test was proven by
    restoring the old cmd /c start shape and watching it go red.
    "It's a local-only backend" is mitigation, not absolution: it is one --host flag from a LAN.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.60.1-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.60.1.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.60.1-docs.zip -- the generated documentation site.

What's Changed

Full Changelog: v2.60.0...v2.60.1

v2.60.0

Choose a tag to compare

@github-actions github-actions released this 13 Jul 02:04
2cb522e

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-12 — 2.60.0 — The verdict: 1000 prompts render in 253 ms on a phone, with flat memory

The number the whole exercise existed to produce, from the release APK on a real Android runtime:

Roll engine render memory jank
20 1497 ms 383 ms 112 MB 95.7%
200 5447 ms 196 ms 122 MB 92.7%
1000 23366 ms 253 ms 110 MB 89.8%
The list virtualizes exactly as promised: 50× the rows costs no more memory (110 MB vs 112 MB) and
no more render time (253 ms vs 383 ms), and the cost per prompt falls with N (94 → 28 → 24 ms). The
jank is the emulator's software GPU — identical across all three rolls, which is precisely why the gate
judges each roll against the same device's own baseline rather than an absolute frame budget.

2026-07-12 — 2.60.0 — …and the "defect" it first reported was my test

The on-device gate's first runs said the app missed its headline promise: 1000 prompts, no
"1000 generated" inside ten minutes. For a few hours the notes said so. It was wrong, and what
proved it was the instrumentation added to diagnose it:

[rap-perf] roll 1000 prompts: 13044ms (engine only)
[rap-perf] committed 1220 result rows      ← 34 ms later

The engine produced all 1000 prompts — 13.0 s on a software-rendered CI emulator, linear across 20 → 200
→ 1000 — and React committed every row 34 ms later. Nothing was slow.
The bug was in the test: results accumulate across rolls (each batch is prepended, by design), so
after the 20-prompt baseline the label reads "220 generated", and a test waiting for "200 generated"
waits forever. It then burned a ten-minute timeout per roll and reported that as the app failing. The
suite now clears the list before each roll (new clear-all testID).
Two lessons, both now in the notes:

  • The test's verdict was louder than the app's evidence, and I believed the test. The [rap-perf]
    lines were sitting in the log the whole time. Read the instrument you built before you distrust the
    thing it measures.
  • It retires the 2026-07-11 conclusion that FlashList's web renderer was to blame for the same
    symptom in the proxy. scripts/probe-mobile-list.mjs: the export renders 1000 prompts in 165 ms with
    16 rows mounted in the DOM
    . That explanation was comfortable and false.

2026-07-12 — 2.60.0 — CI gets two tiers: fast on every push, expensive on the release path

Owner: "only use CI for things that don't take a lot of time; things that take a lot of time should be
gated for release/ship/deploy only."

The android-device job compiles the Android app from source and boots an emulator — 30–45 minutes. Run
on every push to dev, it made each one-line iteration a 40-minute wait (and, this session, several of
them). It now runs where it actually protects something: the pull request into main, pushes to
main, and workflow_dispatch. main still cannot take a build it rejects — the release PR must be
green — while dev stays fast. A gate that makes iteration miserable is a gate people learn to ignore.

2026-07-12 — 2.60.0 — The harness itself (Detox on a real Android runtime)

The mobile testing mandate had one honest exception, and this closes it. The app promises 1000
prompts in a single roll with no performance loss — a claim about a phone. The react-native-web
proxy could never check it: it runs FlashList's web renderer, which doesn't recycle like the native
one, so any number it produces describes react-native-web. The test was kept skipped, with the
measurements inline
, rather than deleted (pretending) or left failing (crying wolf).
Now there's a real harness: targets/mobile/e2e/ + .detoxrc.js — Detox driving the release APK
(built from the Expo-CNG native project, which stays gitignored) on an emulator; local via the
rap_phone AVD, in CI via a new android-device job (KVM-accelerated Ubuntu runner).
What it asserts, and why it can't be gamed. Not "1000 prompts in under N ms" — that benchmarks
whatever box CI got. It rolls 20, then 1000, on the same device in the same session, and
compares: a virtualized list holds a window of rows, so 50× the data must not mean 50× the memory or a
collapsed frame rate. The evidence is the platform's own accountingdumpsys gfxinfo (janky-frame
%, p50/p90/p95/p99) and dumpsys meminfo (real PSS) — not a stopwatch inside the test. Emulator noise
is identical in both rolls and cancels. It also pins that the app produced all 1000 (the wait is on
the literal "1000 generated", so a re-introduced cap times out rather than passing quietly) and that
the app is still interactive afterwards.
Also: gradle/ndk-override.init.gradle — an opt-in escape hatch (ANDROID_NDK_VERSION) so a local
build uses an NDK you already have instead of stalling for hours on a 700 MB download of the exact
pinned one. No-op in CI.

2026-07-12 — 2.60.0 — De-dup, the last one: engine/dplInsertCatalog.js

The DPL insert catalog describes what engine/core/dpl/dpl.js compiles — the constructs, their
syntax, their templates. That is the engine's grammar; it was never the web target's to own, and the
phone's 262-line hand-port existed only because the web owned it (guarded by checkDplInserts).
The plan called this one "entangled", because the web localizes the menu's labels through react-intl
while mobile inlines English — sharing the module naively would have dragged react-intl into React
Native. The split that resolves it generalizes: grammar is shared, presentation is not. The engine
holds ids / syntax / templates / examples / materializeTemplate; each target attaches its own label
layer via buildInsertMenu({category, item}). Label keys are derived from the catalog ids, so a
construct added to the grammar with no string in a target fails tests/unit/dplInsertCatalog.test.js
instead of rendering undefined on a phone.
Mobile 262 → a label table; web 264 → 24. checkDplInserts deleted — six of the seven drift checks
are now gone, each because the thing it guarded can no longer differ.

2026-07-12 — 2.59.1 — The local gate was a SUBSET of the CI gate (CI had been red, unseen)

gh run list on dev: CI failing since the previous session's last push — on Format check.
Nine files that session wrote were never Prettier'd, and npm test ran lint but not format:check,
which CI does. So the session ended "green" on a commit CI rejects. A gate you don't run is not a gate
— and a local gate that is a subset of the CI gate is a lie about what green means.
format:check now
runs inside npm test.
Two of the nine were generated files, and that exposed a deadlock: hand-formatting them made
check:registry call them STALE (it compares byte-for-byte against the generator's output), while
leaving them made format:check red — two gates each demanding the other be broken. Fixed at the
source: scripts/build-provider-registry.mjs runs its rendered output through Prettier before writing
and before comparing. Never hand-format a generated file.

2026-07-12 — docs — The notes are the system of record (working-agreements §A0)

Owner: "look in the notes please — use them by default and grow accustomed to them by default."
Written down as a hard rule, in both places an assistant actually reads: CLAUDE.md's Start Here
is now an ordered session-start ritual (status.md → the latest session log → the plans//systems/
page for the area being touched), and working-agreements.md gains §A0 — notes read first, used as
the default source of truth over any private/AI memory, written back in the same change. Also refreshed
the CLAUDE.md notes index (it still said "there is no automated suite yet").

2026-07-12 — 2.59.0 — De-dup: the building-block catalog → engine/blockCatalog.js

The token cloud + the DPL autocomplete are engine domain: they describe the engine's own content
pools, their folder categories, the virtual {#any} / {keyword} wildcards, the NSFW gate, and the
naming rules. Nothing about that is a UI concern — the UI just renders what it returns. And it's a pure
function of a loader, which is precisely why it could be shared: each target passes its own
(runtimeLoader in the browser, metroLoader on the phone).

  • targets/web/frontend/lib/promptEngine.js: 411 → 219 lines.
  • targets/mobile/lib/blockCatalog.js: 218 → 33 lines (a hand-port with no drift check at all
    the worst case, because nothing would have noticed the phone's palette falling behind the web's).
    Replaced with a real test (tests/unit/blockCatalog.test.js, 9): the catalog's rules ({#any} leads,
    {salt} trails, {keyword} exists, NSFW hidden by default and additive when adult is on,
    expansion/ never listed), the completion flattening, and — the one a hand-port could never give you —
    that the phone never invents content the engine doesn't have.
    Two things that test taught me, both worth keeping:
  • I first asserted a byte-identical catalog across the two loaders. It failed on {#beach-merk}, and my
    instinct was "mobile is missing a block". It wasn't: that's the repo-root user/ overlay, a
    desktop-only content pool (the phone's user content is its on-device Manage overlay). The test
    was wrong, not the app — so I asserted the real invariant rather than weakening it until it passed.
  • The comparison then failed intermittently because metroLoader carries a module-level runtime overlay
    and a sibling suite left one installed. Reset it in beforeAll; run the suite twice to prove it's
    order-stable.
    Also: 43 coverage artifacts had been committed in 2.58.0 (targets/mobile/coverage/ wasn't
    gitignored, tho...
Read more

v2.52.0

Choose a tag to compare

@github-actions github-actions released this 11 Jul 00:04
944f6d4

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-10 — Address CodeRabbit review across the mobile target (2.52.0)

Worked through the mobile-app review findings so the 2.52.0 PR's conversations resolve on merit:

  • Stability/timeouts: a shared fetchWithTimeout (AbortController + 120s, merges any caller signal)
    now backs every network call in lib/imageProviders.js; lib/storage.js races remote downloadAsync
    against a 60s timeout so a stalled https: source can't hang saveImageSrc; lib/keys.js setKey
    returns a success flag and the BYOK key field warns on a failed keystore write instead of looking
    saved.
  • Error handling: GalleryScreen surfaces a load failure with a Retry (no more infinite "loading…")
    and wraps deleteSelected; SingleScreen doConvert gained the busy guard + serialization its
    doResize/doUpscale siblings already use.
  • Correctness: GenerateScreen insert-menu / block-palette tokens now target the active field
    (Prompt or Negative), and result-row ids use a monotonic per-click batch counter so a fixed
    promptSeed can't collide ids and misattribute images across rows; the "Rewriting…" status always
    clears on the copy/no-provider path.
  • Polish: ComfyUI batch_size floor-clamped to ≥1 (parity with the WebUI path); custom list names
    disallow / (they wouldn't round-trip in the flat lists dir); index.js uses an explicit ./App.js
    import extension.

2026-07-10 — CodeRabbit review: harden mobile-parity tooling + metroLoader test

Addressed the CodeRabbit review items on the release-hardening code itself. The visual-parity dev server
now guards decodeURIComponent (a malformed escape like /% no longer crashes it before the fs try
blocks); build-metro-catalog.mjs derives generated .js import specifiers from the OUTPUT file's
directory (so a custom --out resolves correctly) instead of a hardcoded ../data/blocks/; and
tests/mobile/metroLoader.test.js tightened its known-value assertions (toBeTruthy + explicit
object-or-null / never-undefined checks) so a loader regression returning undefined can't slip past
not.toBeNull() / not.toThrow().

2026-07-10 — Release-harden 2.52.0: use the CodeQL-recommended path-traversal sanitizer

Follow-up to the traversal fix: containment guards (ternary, then early-return startsWith) were both
logically correct but CodeQL's taint tracker still saw req.url-derived data reach statSync/
readFileSync and kept the 3 high js/path-injection alerts. Switched to the exact sanitizer form the
js/path-injection help recommends — normalize() the request, strip any leading ../ / ..\
segments, then join under OUT — which CodeQL recognizes as sanitizing. Verified every traversal
variant (raw, ..%2f, %2e%2e, interior ../) stays inside the served directory; normal assets
resolve unchanged.

2026-07-10 — Release-harden 2.52.0: remove mobile dead code + align test assertions

Cleared the CodeQL "unused" notes and SonarCloud Reliability/Maintainability findings that blocked the
2.52.0 release PR — real cleanup, no gate-silencing. Removed 8 unused imports/variables in the mobile
target (App.test.jsx top-level Text, BlockPalette.test.jsx an unused getByText destructure,
GenerateScreen.test.jsx waitFor, lib/icons.js G, GenerateScreen.js ShuffleIcon,
SingleScreen.js TextInput + promptText imports + the upscaleProvider theme destructure). In
tests/mobile/single.test.js, aligned the three numeric detail assertions (Steps/CFG/Seed) with the
string-valued Object.fromEntries map Sonar infers, and switched toBe(null)/.length).toBe() to the
dedicated toBeNull/toHaveLength matchers.

2026-07-10 — Release-harden 2.52.0: earn metroLoader Node coverage (race-free)

Reverted the engine/core/metroLoader.js coverage exclusion (silencing a real gap) and instead EARNED
its coverage with tests/mobile/metroLoader.test.js — exercises every accessor and proves the loader
drives createEngine byte-identically to nodeLoader; metroLoader.js is now measured (~87%) rather
than hidden. Only the generated, gitignored engine/core/metroCatalogData.js stays excluded (data, not
logic), and it's now also excluded from Sonar analysis/coverage/duplication so the CI-built blob isn't
scanned. Made the parity check deterministic by moving the catalog build + a clean-state snapshot of
nodeLoader's names and parity generations into a Vitest globalSetup
(tests/setup/metro-catalog.globalSetup.js), captured before any worker spawns — so it can no longer
race manageFs.test.js's transient shared-FS fixtures or a concurrent-read scan miss on Windows.

2026-07-10 — Release-harden 2.52.0: fix path traversal in the mobile visual-parity server

CodeQL flagged three high-severity "uncontrolled data in a path expression" alerts in the mobile
visual-parity dev server (scripts/mobile-visual-parity.mjs): req.url flowed straight into
join(OUT, …)statSync/readFileSync with no boundary check, so GET /../../etc/passwd could
escape the served directory. The server now resolves each request under an absolute OUT_ROOT and
rejects anything that leaves it (falling back to index.html), blocking raw and URL-encoded
(..%2f, %2e%2e) traversal while normal asset paths resolve unchanged.

2026-07-10 — Mobile: full Single-view parity + first automated test layer (2.52.0)

MINOR milestone. Rounds out the mobile (Android/Expo) target to web parity on the Single view and
stands up its first automated tests. See the detailed entries below; in brief: SingleScreen rebuilt to
full parity with the web SingleView (nav, layered prompt/negative, inline re-roll/variation, convert/
resize/upscale, lineage + derived strips, details/raw-JSON/copy, keyword cloud), the Generate/Gallery
parity gaps closed, and a jest-expo + React Native Testing Library suite (64 tests) covering every
mobile screen, menu, and lib module — wired into npm test (test:mobile). targets/mobile excluded
from the root ESLint + Prettier (Expo owns its own toolchain), matching targets/web.

2026-07-10 - Mobile: component tests for every screen/menu + lib unit tests

Completed the mobile automated test layer to the web suite's "every module covered" bar. 64
mobile-specific tests, all green:

  • Component (jest-expo + RNTL, 40 across 10 suites): App shell (tabs + ⋯ overflow), SingleScreen,
    GenerateScreen, GalleryScreen, ManageScreen, OverflowMenu (three-role picker / appearance / language
    over the real registry), InsertMenu (DPL construct drill-in + insert), BlockPalette (search + groups +
    chip insert), plus lib keys (secure-store) and storage (file-system index).
  • Unit (root vitest, 24 across 2 files): lib/single.js (16) and lib/imageProviders.js registry /
    defaults / systemFor / structural invariants (8).
  • Added accessibilityLabels to the remaining icon-only buttons (App ⋯) — a11y parity + test handles.
    jest.setup mocks safe-area (useSafeAreaInsets), status-bar, and FlashList (header + rows + empty).

2026-07-10 - Mobile: component tests extended to Generate / Gallery / Manage

Grew the jest-expo + RNTL suite from Single to every screen (20 tests, all green): GenerateScreen
(composer renders, rolling fills the results feed, the gear opens the full settings sheet, live
preview), GalleryScreen (header/count/search/select/refresh/composer, search filter, multi-select,
empty state), ManageScreen (lists master view, create-opens-editor, open windowed editor, delete,
empty state). Added accessibilityLabels to the icon-only buttons exercised (Generate, Prompt
settings, Toggle live preview, Generate-here) — an a11y-parity gain with the web's aria-labels as well
as test handles. The shared FlashList test mock now renders ListEmptyComponent, and the safe-area
mock exports useSafeAreaInsets.

2026-07-10 - Mobile: jest-expo + RNTL test harness; component + helper tests

Stood up the mobile target's first automated test layer (it had none) to the bar of the web suite —
real component tests that mount the actual RN screens (the Android code path) through the jest-expo
renderer with native modules mocked:

  • Harness: jest-expo preset + @testing-library/react-native + pinned react-test-renderer
    (19.1.0, matching React 19.1.0); jest.setup.js mocks the native leaves (expo-image, FlashList,
    expo-file-system/legacy, expo-image-manipulator, expo-media-library, expo-sharing, expo-clipboard,
    expo-secure-store, safe-area-context). Run via npm --prefix targets/mobile test, wired into root
    npm test as test:mobile.
  • Single component tests (screens/__tests__/SingleScreen.test.jsx, 7): mounts the real screen and
    asserts nav/position/tools render, the layered Prompt+Negative cards render from metadata, the details
    table renders, the keyword cloud fires search, inline Re-roll fires the provider's generate adapter,
    Back invokes its callback, and the empty state shows.
  • Single helper unit tests (tests/mobile/single.test.js, 16, root vitest): layer normalization
    (enriched + legacy), buildDetails, parseKeywords, linkChildren, sizeFromSettings, toMarkdown,
    searchHaystack.
  • Excluded targets/mobile/** from the root ESLint (Expo has its own toolchain), matching targets/web/**.

2026-07-10 - Mobile: Single view rebuilt to full web parity; Generate/Gallery gaps closed

Comprehensive web-to-mobile comparison of the remaining surfaces (SingleView.jsx + its subcomponents,
PromptComposer, Gallery), then brought the mobile app to parity:

  • Single (screens/SingleScreen.js, rebuilt): prev/next nav + position, open-full viewer, share
    (expo-sharing) / save-to-Photos (expo-media-library) / delete overlay actions, Convert (format) +
    Resize (scales) + AI Upscale via expo-image-manipulator, lineage header + par...
Read more

v2.51.1

Choose a tag to compare

@github-actions github-actions released this 09 Jul 03:28
6ec3e54

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-09 — Fix the DPL editor's white gutter + washed-out active line in dark mode (2.51.1)

The live editor showed a bright-white line-number column and a milky blue active-line band in dark
mode. Root cause: CodeMirror 6's gutter baseTheme ships both &light .cm-gutters {#f5f5f5} and a
&dark variant, chosen by whether the view's theme declares { dark: true } — and our editors never
did. So CM stayed in light mode and injected the light gutter (#f5f5f5), the light active-line
gutter (#e2f2ff), and the milky active-line wash (rgba(204,238,255,.267)) at the SAME specificity
as our .dpl-editor .cm-* CSS, beating it on source order. A plain-CSS override could never win.

  • New shared theme extension (targets/web/frontend/lib/editorChrome.js): a CodeMirror
    EditorView.theme (StyleModule priority > baseTheme, so it wins) that sets a transparent gutter
    with dim recessed numbers, a brighter neutral active-line NUMBER, a whisper-subtle neutral
    active-line lift (4.5% of --fg), and the accent-tinted selection. Colors are the app's CSS
    variables, so the chrome tracks light/dark on its own (no hard-pinned dark flag).
  • Wired into both editorsDplEditor.jsx (the prompt boxes) and CodeEditor.jsx (Manage's
    code/list editors, which had NO gutter override and showed the same white slab).
  • Dropped the dead CSS in dpl-editor.css (the losing .cm-gutters/.cm-activeLine*/selection
    rules), leaving a comment that explains why the chrome lives in the theme now.
  • Regression test tests/e2e/editor-chrome.spec.js — asserts (dark scheme) a non-light gutter
    surface and a neutral, untinted active-line band. Verified visually at prompt.fairyfox.io parity in
    dark AND light mode.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.51.1-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.51.1.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.51.1-docs.zip -- the generated documentation site.

What's Changed

  • Release v2.51.1 by @junebug12851 in #48

Full Changelog: v2.51.0...v2.51.1

v2.51.0

Choose a tag to compare

@github-actions github-actions released this 08 Jul 11:34
0f8705a

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-07 — Pre-release hardening: preset-loader path-traversal fix + engine-module coverage (2.51.0)

SonarCloud (on the 2.51.0 release PR) flagged the new shared engine modules — fixed for real before
shipping rather than merging a red gate:

  • Security (path traversal). engine/presets.js loadPreset(name) built a file path from name,
    which arrives from the /api/prompt request body — so a crafted preset with ../separators could
    read arbitrary *.json files. It now rejects anything but a plain preset name. Regression-tested.
  • Coverage. The three new modules (promptRun.js / nodeEngine.js / presets.js) weren't in the
    Vitest coverage allowlist, so Sonar saw 0% on them. Added them + focused unit tests
    (tests/unit/{promptRun,presets,nodeEngine}.test.js) → ~100% lines each; global thresholds hold.
  • False positive. Suppressed S2245 (Math.random) for promptRun.js's batch-seed mint — a creative
    prompt seed, never security-sensitive (same as the existing rng.js / random.js suppressions).
    Full gate green (419 web + the Node suite incl. the new specs).

2026-07-07 — New targets/comfyui/ target: ComfyUI prompt-engine nodes (2.51.0)

Added a ComfyUI custom-node target (targets/comfyui/) that brings the prompt engine into ComfyUI as
natural-language-first STRING sources for a CLIP Text Encode. Prompt-side only — ComfyUI already
owns image generation, upscaling, variations, and re-roll (its native seed widget), so the target adds
just the prompt half (the DPL processor, blocks, lists, presets).

  • Thin Python wrappers, no re-ported engine logic. The nodes make HTTP calls to a running app's
    local backend (point-at-running-app; default http://localhost:4173, auto-detects a running app on
    localhost:4173/5173, override via a Settings field / RANDOM_AI_PROMPT_URL). Two new backend routes power it —
    POST /api/prompt and GET /api/prompt/catalog — reusing the shared engine/promptRun.js,
    engine/nodeEngine.js, and engine/presets.js (all extracted this session so nothing is duplicated;
    the CLI re-exports the same modules). Dependency-free (stdlib urllib).
  • Nodes: a flagship natural-language RandomAIPromptGenerator (template + seed + nsfw + preset) plus
    helpers PromptList / PromptBlock / DPLExpand / PromptBatch (N variations as a list) /
    CombinePrompts (join wired pieces) / ShowPrompt (display + pass-through). Re-roll is the native seed
    widget (control_after_generate); presets come from engine/data/presets (+ user/presets). Every
    input/output carries a tooltip + each node a description; the generator is top-level, the helpers grouped
    under a submenu. (An AI-rewrite node was considered and dropped — calling a third-party API mid-graph is
    off-paradigm for ComfyUI, and the plugin now makes zero third-party calls.)
  • Frontend extension (web/randomAiPrompt.js): the single Settings URL field (drives dropdowns and
    generation via a persisted /random_ai_prompt/config), LIVE dropdowns from the catalog (same-origin
    proxy routes, avoiding CORS), the app icon + brand colours on the nodes, the ShowPrompt text display,
    and a status sidebar. Plus a drag-in example_workflows/ starter and an Apache-2.0 LICENSE.
  • Verify: the engine/backend side is covered by tests/integration/promptApi.test.js (generate, seed
    reproducibility, preset apply + unknown→400, catalog); the Python + ComfyUI-runtime JS are
    syntax-checked and must be validated in a running ComfyUI (manual — no CI runtime). Full gate green.
    New deep-dive systems/comfyui.md; credits + CLAUDE.md updated; legal pages
    re-checked (localhost only — no third-party data flow).

2026-07-07 — Dispose of the chaos knob; extract a shared engine-owned prompt-run (2.50.1)

Removed the chaos value for good. It was a pre-DPL knob for controlling randomization (scaling the
whole emphasis/editing/alternating envelope at once, with blocks meant to react to it) that predated the
DPL wrapper and was never liked; it was never an engine setting (engine/settings.js never had it), and
its UI control had already been unmounted on 2026-06-19. Deleted withChaos from the web facade
(targets/web/frontend/lib/promptEngine.js) and the CLI, dropped the CLI --chaos flag
(optionSpec.js), and swept the current-state docs (removed-pending-readd.md row deleted; status.md,
cli.md, dpl-language.md, prompt-dsl.md, next-steps.md, the Home.jsx comment). Left untouched:
Midjourney's own unrelated --chaos provider parameter, and the word "chaos" in the vocabulary lists /
block descriptions. Default prompt output is byte-identical (withChaos was a no-op at chaos = 1); the
snapshot + CLI reproducible-prompt tests confirm it.
In the same pass, extracted the duplicated seed/reroll prompt-run logic into a new engine-owned,
isomorphic module engine/promptRun.js (seedFor, forEngine, and a createPromptRun(engine)
factory). The web SPA facade and the CLI's promptRun.js now consume it instead of each carrying their
own copy — so the seed rules live in one place, and the upcoming ComfyUI backend prompt route can reuse
them rather than re-porting the logic a third time. No behavior change: 293 Node + 419 web tests, lint,
and doc-link checks all green.

2026-07-07 — New targets/cli/ target: the prompt command-line tool (2.50.0)

Added a command-line build target — a traditional args-and-flags CLI (prompt, package
@random-ai-prompt/cli) that generates prompts and runs them through image providers using the same
engine, providers, settings, and on-disk store as the web/desktop app
(parity with both the engine
and the GUI, by default). No TUI/interactive mode — every capability is a subcommand with flags, a
--help page, colored output (picocolors; honors NO_COLOR/FORCE_COLOR), and completion for
bash, zsh, fish, and PowerShell.

  • Commands: generate (default; every engine/settings.js field is a flag, plus provider/image/
    rewrite knobs, --seed/--random, --nsfw, --preset, --json), list
    (blocks/lists/providers/presets/dialects/samplers/settings), config, keys, rewrite, upscale,
    and completion.
  • Reuse, not fork: a Node provider registry (src/lib/providers.js) replaces the SPA's Vite-glob
    registry (fs-discovers shared/<id>/config.js + _shared/settings/*.js); the CLI runs the real
    backend (apiHandler.js) in-process on an ephemeral port with a fetch shim, so every
    provider's own code/generate.js runs unchanged and images save to the shared output/ folder with
    the same sidecar the gallery reads. An ESM resolve hook (src/lib/jsonLoader.mjs) injects
    type: json so the providers' bare JSON imports load under Node.
  • Shared state: CLI defaults persist to their own cli namespace (never clobbering the GUI's
    settings.json); BYOK keys are read from both stores, so keys are shared between the CLI and the app
    (or supplied per-run via PROMPT_KEY_<PROVIDERID>). An api provider is only called with --images,
    so a plain prompt -p openai "x" never spends credits.
  • Wiring/tests: root postinstall installs the CLI; npm run cli runs it; the root ESLint gate
    now lints targets/cli (Node ESM) and CLI unit tests live in tests/cli/cli.test.js (14 tests, in
    the root Vitest gate). See systems/cli.md.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.51.0-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.51.0.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.51.0-docs.zip -- the generated documentation site.

What's Changed

  • Release v2.51.0 — ComfyUI target + headless prompt routes by @junebug12851 in #47

Full Changelog: v2.49.6...v2.51.0

v2.49.6

Choose a tag to compare

@github-actions github-actions released this 07 Jul 05:30
5ea0761

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-06 — Tone down the DPL editor's active-line + line-number gutter on dark (2.49.6)

Follow-up to 2.49.5: the active-line highlight was a color-mix(--accent 7%) band that read as a milky,
washed-out mint slab on the dark theme, and the line numbers used full --faint with a bright --accent
active number — both too loud. Reworked to be quiet and neutral: the active-line body is now a
whisper-subtle color-mix(--fg 3.5%) lift (theme-adaptive, no color cast), inactive numbers are dimmed
(--faint at 55% alpha) so they recede, and the active line's number is a clean neutral --muted
brighten instead of the glowing accent. Verified in Chrome on the dark theme (mid-editor active line +
gutter). CSS-only.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.49.6-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.49.6.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.49.6-docs.zip -- the generated documentation site.

What's Changed

  • Release v2.49.6 — quiet DPL editor active-line/gutter on dark by @junebug12851 in #46

Full Changelog: v2.49.5...v2.49.6

v2.49.5

Choose a tag to compare

@github-actions github-actions released this 07 Jul 05:11
8eb4137

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-06 — Interactive DPL editor layer: hover dials, + line actions, gutter, coloring (2.49.5)

A standardized interactivity layer added to the shared DplEditor (so every prompt box — regular /
negative / gallery / Manage — gets it at once):

  • Hover intensity/focus dials. Resting on a {#…} block reference floats two little speedometer
    dials above it (INTENSITY, FOCUS), 50 dead-center / straight-up. Dragging (or double-clicking) writes
    iNN% / fNN% back into that one reference; landing on exactly 50 (the default) drops the argument so
    the reference stays clean. New lib/dpl/dplDials.js (a plain CodeMirror ViewPlugin; the panel is
    position:fixed on document.body so it never clips, re-anchored on scroll + after each edit).
  • + context-aware line actions. A + sits in a left gutter on the hovered/cursor line; clicking it
    opens a menu that adapts to context: inside the --- front matter → front-matter keys + blank-line
    inserts; the first line with no front matter yet → "Insert front matter"; a line with content →
    "Promote to…" (wrap as - / maybe / NN% chance / otherwise / [weight] / [i<NN%]); always →
    "Replace line with…" (every line-type template), insert blank line above/below, and "New section…"
    (standard Start / Auto Begin / Auto End, or a custom one). New lib/dpl/dplLineActions.js.
  • Line numbers + active-line highlight. lineNumbers() + highlightActiveLine() /
    highlightActiveLineGutter(), themed via the --* tokens in dpl-editor.css.
  • Syntax-coloring gaps closed (dplLanguage.js tokenizer): the insert js: path now colors as a
    ref; otherwise NN% / otherwise maybe colors the whole gate; the (NN% nothing) choice miss is part
    of the choice keyword; and a combined [100 i<10% f<40%] weight/condition bracket colors as one dial
    unit (was previously mangled).
  • New localized strings live in lib/dpl/dplInteractiveMessages.js (formatted through intl and passed
    into the plain-CM extensions). Verified in Chrome across all four editors; full headless gate green
    (lint incl. stylelint, smoke, 416 web tests incl. the SSR prerender guard, web build).

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.49.5-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.49.5.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.49.5-docs.zip -- the generated documentation site.

What's Changed

  • Release v2.49.5 — interactive DPL editor layer by @junebug12851 in #45

Full Changelog: v2.49.4...v2.49.5

v2.49.4

Choose a tag to compare

@github-actions github-actions released this 07 Jul 03:19
7fd544e

Random AI prompt + image generator for the Stable Diffusion WebUI -- a CLI and a local web UI.

Pre-release software. Provided as-is under Apache-2.0.

What's new in this release

2026-07-06 — Fix Manage add-menu overflowing the pane (2.49.4)

The tree's add (+) menu ("New block / New folder") opened left-to-right (left: 0) from + controls
that sit near the right edge of the narrow tree pane, so the 130px menu spilled past the pane and forced
a horizontal scrollbar. Right-aligned it (right: 0; left: auto) so it grows leftward and stays inside
the pane. Verified in Chrome. CSS-only.

2026-07-06 — "Create override" for built-in blocks/lists + corner scrollbar fix (2.49.3)

  • Create override: the block + list editors now show a Create override button for any built-in
    entry. It copies the entry (content + .js/.json sidecars) into the matching user-overlay root
    (user/blocks or user/lists) — which wins at runtime and survives app updates — then selects the
    new copy so you edit YOUR version; the built-in is left untouched. If an override already exists it
    just opens it. Backed by a new cross-root copy fs op (toRoot) in manageFs, overrideEntry in
    useManageTree, and a confirm dialog. Verified end-to-end in Chrome.
  • Corner scrollbar fix: the Modify/Draft combo overlapped the DPL editor's vertical scrollbar —
    inset it (right: 1.25rem) so it always clears the scrollbar.
  • Editor-freeze fix: the first attempt used scrollbar-gutter: stable on the CodeMirror scroller,
    which put CM into an infinite measure loop and froze the renderer when a block opened. Dropped it (CM
    wraps long lines inside the scrollbar already, so the text stays clear without it).
  • Verified green: the full gate — check:docs + lint (incl. stylelint) + smoke + Node unit (279,
    incl. the new cross-root copy round-trip) + web (416, incl. overrideEntry cases) + the web build;
    i18n:extract synced en.json. Manually confirmed the override flow, the scrollbar clearance, and
    the freeze fix in the browser.

2026-07-06 — Refine bar UX overhaul: stepper combos + corner Modify/Draft (2.49.2)

Rebuilt the block refine controls after they read as "a slab of buttons overflowing with even more
buttons oddly below it" (verified in Chrome this time — the fix is UX-driven).

  • Stepper combos: each dimension is now ONE compact control — [ − Detail + ] — instead of two
    separate "Add detail" / "Trim detail" pills. Five combos (Detail, Complexity, Focus, Intensity,
    Variety) + a lone Cleanup pill (renamed from "Tighten") sit on one tidy, wrap-safe row. New
    DplRefineBar renders /+ step buttons per dimension; the +/− aria-labels carry the old action
    names.
  • Corner Modify/Draft: the free-text box moved out of a full-width slab into a joined Modify /
    Draft
    combo pinned to the DPL editor's top-right corner (new DplAskCorner.jsx), opening a compact
    popover (title + textarea + Send, ⌘/Ctrl+Enter). The editor content gets a top gutter so the first
    line clears the control; the popover caps at min(88vw, 360px).
  • Test-infra fix: the heavier suite tipped promptEngine.integration's ensureCatalog() warmup
    hook (~9.3s on HEAD) past the default 10s hook timeout under parallel load — gave that beforeAll a
    30s timeout (the real data-corpus glob genuinely takes >10s under load).
  • Verified green: inspected in Chrome at desktop (combos tidy, corner popover clean, no clipping) +
    lint + smoke + the full web suite (412 tests) + the web build; i18n:extract synced en.json.

2026-07-06 — Free-text "Modify" box for block refine in Manage (2.49.1)

Added a free-text message box to the block editor's refine bar so a template can be re-processed by a
typed instruction — full control alongside the quick pills. A segmented Modify / Draft new toggle
sits over one input: Modify (default) sends your instruction plus the current template to the AI and
applies the revised DPL; Draft new is the previous draft-from-description (now folded into the same
box). Both keep the existing validate + dirty-until-Save + one-click Undo behaviour.

  • New dpl-custom mode (rewriteSystem.js): its task tells the model the user message is an
    INSTRUCTION followed by the current template after a --- TEMPLATE --- delimiter, to apply the
    change and return the full revised DPL while preserving everything not asked to change. Rides on the
    same DPL_PRIMER as the other dpl-* modes.
  • dplRefine.js: DPL_CUSTOM_MODE + buildCustomPrompt(instruction, template) (packs the two
    around the delimiter). DplRefineBar.jsx replaced the collapsible draft control with the always-
    visible Modify/Draft box; ManageBlockEditor.jsx gained handleCustom (validates both an
    instruction and a template exist, composes the prompt, runs dpl-custom) and a kind-driven status.
  • Verified green: lint + smoke + the full web suite (409 tests) + the web build; i18n:extract
    synced en.json. No data-practice change, so the legal docs are untouched.

2026-07-06 — AI refine + draft-from-description for blocks in Manage (2.49.0)

Extended the Manage block editor's DPL tab with an AI refine toolbar and a draft-from-description
control, so a block template can be shaped by clicking instead of hand-editing DPL. All of it rides on
the existing text (rewrite) provider path — the same BYOK plumbing the list editor's "AI Expand" uses —
so no new provider code was needed.

  • Refine toolbar (DplRefineBar.jsx): five dimensions as more/less pill pairs — Detail
    (add/trim), Complexity (more/simplify), Focus (sharpen/loosen), Intensity (crank/ease),
    Variety (more/consistent) — plus a Tighten polish action. Each pill sends the current template
    through the provider with a dedicated dpl-* mode and replaces the editor content; the result is
    validated (issue count surfaced in the status), marked dirty (not saved until Save), and reversible via
    an Undo link (a manual edit supersedes the revert point).
  • Draft from description: a free-text box drafts a whole starting template from a plain-English
    subject, using a "winning formula" system prompt (front matter → Start → subject spine → essential
    bullets → one of: variety → maybe/NN% garnish → [f<40%] focus fluff → [i>70%]/[i<25%]
    intensity variants, composable, ~10–20 lines).
  • DPL-aware system prompts (rewriteSystem.js): a shared DPL_PRIMER teaches the model the DPL
    grammar and the intensity/focus dials so it refines as DPL (tokens, sections, gates, choices
    preserved) rather than flattening to prose; systemFor() now routes every dpl-* mode (primer + a
    per-mode task) alongside the existing keyword/expand/fix. Reused by both transports
    (browser-direct + the /api/rewrite proxy) since both already call systemFor.
  • New: frontend/lib/dpl/dplRefine.js (action catalog + cleanDplOutput fence/quote stripper) and
    dplRefineMessages.js; styles/components/dpl-refine-toolbar.css. No data-practice change (refine
    reuses the already-disclosed text-provider flow), so the legal docs are untouched.
  • Verified green: lint + smoke + the full web suite (404 tests, incl. new dplRefine,
    rewriteSystem, and DplRefineBar specs) + the web build; i18n:extract synced en.json.

How to get it

Prefer not to build? Download a pre-built edition:

  • Desktop app -- Windows .msi / .exe (or a portable .zip), macOS .dmg, Linux .AppImage / .deb (attached below). Self-contained; nothing to install first.
  • random-ai-prompt-2.49.4-online.zip -- the online edition as static files; host it anywhere, or just use https://prompt.fairyfox.io.
  • random-ai-prompt-2.49.4.tar.gz -- source tarball (run with Node 24: npm install then npm start).
  • random-ai-prompt-2.49.4-docs.zip -- the generated documentation site.

What's Changed

  • Release v2.49.4 by @junebug12851 in #44

Full Changelog: v2.48.0...v2.49.4