18 Commits

Author SHA1 Message Date
Alex Dunmow
71d005f1fb feat(bnp): marshal public_routes + sitemap into built manifests (ADR 0026)
pluginsdk v0.2.7. The packer validates public_routes (reserved
prefixes, traversal, duplicates), requires an HTTP handler for routes
or sitemap, and stamps both into manifest.pb; codeless builds reject
them; writeMod round-trips the new plugin.mod keys so a version bump
cannot strip live route claims.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 02:45:58 +08:00
Alex Dunmow
4eb4bcfc50 fix(plugin): writeMod drops allowed_hosts/max_response_mb/required_icon_packs
writeMod hand-reconstructs plugin.mod field by field but never emitted three
first-class core.ModFile fields, so ParseModFull → mutate → writeMod (every
bump/init/tags edit) silently stripped them. For allowed_hosts this is
security-relevant: a `ninja plugin bump` erased a plugin's ADR-0023 egress
declaration, the install/update consent gate saw nothing to grant, and the
plugin's outbound calls were denied at runtime with no prompt ever shown.

Emit all three; add a writeMod ⇄ ParseModFull round-trip regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:48:54 +08:00
Alex Dunmow
7cfc371a42 feat(build): stamp allowed_hosts/max_response_mb into the manifest (ADR 0023)
ninja plugin build now validates plugin.mod's allowed_hosts against the
egress host-pattern grammar (failing the build on a bad pattern) and
stamps allowed_hosts + max_response_mb into the packed manifest, the way
data_dir already crosses mod → manifest. Bumps pluginsdk to v0.2.5.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 02:01:45 +08:00
Alex Dunmow
1fb8a634ab chore: pluginsdk v0.2.0 (P3 host-composed chrome)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:56:53 +08:00
Alex Dunmow
f074d71cf9 chore(theme): modernize strings.Split to SplitSeq
Convert two loops in the theme command from strings.Split() to
strings.SplitSeq() for more efficient iteration using Go 1.24+ iterators.
This is a mechanical modernization with identical behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:46:02 +08:00
Alex Dunmow
42789ffd0f refactor: migrate plugin SDK imports from block/core to block/pluginsdk
Rewrite import prefix git.dev.alexdunmow.com/block/core/{plugin,blocks,
templates,abi} to git.dev.alexdunmow.com/block/pluginsdk/* across the CLI's
plugin build/verify logic (internal/bnp), plugin commands (cmd/ninja/cmd),
and the wasm build fixtures (testdata/fixture, testdata/capfixture). go.mod
adds pluginsdk@v0.1.0; core is retained only for cmd/ninja/cmd/theme.go
(ParseModFull), which is left untouched as in-flight work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:39:22 +08:00
Alex Dunmow
4e82b1ef41 fix(login): retry transient poll errors instead of aborting the device flow
A proxy 502 during a backend restart killed attended logins mid-poll.
NotFound/InvalidArgument still fail fast; everything else retries until
the device-code deadline, with a one-time notice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:05:30 +08:00
Alex Dunmow
2b685348c9 feat(login): use account chosen on the device-approval page; stdin picker becomes fallback
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:37:05 +08:00
Alex Dunmow
098a2091b9 feat(theme): --settle capture delay for reveal transitions and canvas heroes
Scroll-reveal themes (gotham .reveal, scifi-clean data-sc-reveal) start
content at opacity:0 under JS and fade in ~0.5s after the observer fires;
capturing on WaitVisible(main) catches mid-transition ghosts. --settle adds
a post-wait delay so transitions and canvas animations (cyberpunk rain)
finish before the screenshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:23:43 +08:00
Alex Dunmow
e71bf16d71 feat(theme): --scale for retina gallery captures
deviceScaleFactor pass-through to chromedp EmulateViewport; --scale 2
produces 2880x1800 PNGs for hidpi store galleries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:21:41 +08:00
Alex Dunmow
dda752bfc1 feat(theme): --modes light,dark for --pages gallery captures
Sets the bn-theme cookie + emulated prefers-color-scheme before navigation
so each page can be captured in both color modes (Wave B screenshot sets).
Mode-suffixed filenames (NN-<slug>-<mode>.png); empty --modes keeps the
old single site-default capture and naming.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 08:53:49 +08:00
Alex Dunmow
ddf2dd59ef chore: rename dev host localdev.blockninjacms.com -> blockninja.dev 2026-07-05 20:50:18 +08:00
Alex Dunmow
b3d86b1489 chore: gitignore build output (bin/)
The ninja binary under bin/ is compiled build output, not source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:41:09 +08:00
Alex Dunmow
b5e39121d2 feat(cli): ninja plugin gallery commands (Phase 6)
Add `ninja plugin gallery list|add|remove|reorder|set-featured` for
author-side curation of a plugin/theme's registry screenshot gallery,
feeding the browse/detail surfaces shipped in Phases 4-5.

- Re-vendor plugin_registry.proto from orchestrator (adds
  PluginGalleryService) and regenerate the connect client.
- Wire the Gallery client into orchclient.Client.
- Target plugin defaults from plugin.mod with --scope/--name overrides;
  device-flow auth via resolveClient. list is a public read; add/remove/
  reorder/set-featured are RoleUser (scope/account membership enforced
  server-side). add derives content_type from the extension against the
  png/jpg/jpeg/webp allowlist and rejects >8MiB client-side.

Scope handling trims a leading @ client-side because ListScreenshots does
not trim server-side (GetPlugin does). Live-verified against the dev
orchestrator; go build + go test ./... + check-safety all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:35:09 +08:00
Alex Dunmow
64d81bd93f docs: add CLAUDE.md (build/install, .bnp packing, vendored proto, dev vs prod host)
The make install landmine (stale binary republishes themes without preview.png
and wipes the live preview), the zstd-tar .bnp format, publish-builds-the-artifact,
the vendored-not-submodule orchestrator proto workflow, and the prod-by-default
--host all live in one place for the next agent working in here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 09:20:17 +08:00
Alex Dunmow
e8aba45f21 feat(bnp): pack preview.png + screenshots/ into artifacts; multi-page capture
The .bnp packers never carried preview.png (the .so-era source archives did
implicitly), so any republish silently wiped a theme's registry preview.
Both builders now pack an optional root preview.png and a screenshots/ dir
(png/jpg/jpeg/webp, <=8MB each, <=12 files, validated), reported in the
build/verify summaries. ninja theme screenshot gains --pages/--screenshots-dir
to capture NN-<slug>.png per gallery page for the registry gallery.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 08:21:35 +08:00
Alex Dunmow
feeb31139d feat: publish builds the .bnp itself — the artifact is the only publish form
ninja plugin publish now runs the build pipeline (codeless or wasm,
same as `ninja plugin build`) and uploads the resulting .bnp; the
legacy source-archive path is deleted (internal/archive removed).
--bnp remains as an optional prebuilt-artifact override.

Client-side guard mirrors the orchestrator verify gate: a non-empty
manifest version that differs from plugin.mod fails before upload.

The git-archive-era publish warnings (gitignored-tracked, untracked,
submodules) described a ship mechanism that no longer exists; replaced
with a single dirty-tree drift warning (--strict still aborts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 02:16:56 +08:00
Alex Dunmow
2f065e3ed4 feat: ninja CLI in its own repo (block/cli, WO-WZ-023)
The ninja developer CLI moves out of block/core into its own module
git.dev.alexdunmow.com/block/cli. Pins block/core@v0.18.2 for abi/v1, the
plugin.mod parser, and DESCRIBE guest builds; vendors its own orchestrator
registry client (internal/api, generated from a vendored plugin_registry.proto)
since it cannot import block/core/internal. Produces byte-identical v1
artifacts (verified: art-deco codeless SHA256-identical to the pre-move build).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 22:39:32 +08:00