feat(publish): add extctl publish — stage, screenshot, and PR extensions to the marketplace - #93
Merged
Merged
Conversation
…ons to the marketplace Closes the last gap in the pipeline: extctl release tags a merged extension and web-extensions' own CI builds a GitHub Release from it, but nothing ever got the extension into owncloud/marketplace, where oCIS actually reads its catalog from. extctl publish scans for released-but-unpublished extensions and, per extension, downloads the release bundle, resolves license/subtitle from its own package.json (never guessed — missing license fails that extension rather than staging a wrong one), resolves tags/minOCIS by reusing the extension's most recent prior marketplace release if one exists, else Claude inference (tags) or git-history inference (minOCIS), else left unset — and generates screenshots via a dedicated Claude-written Playwright spec (never the extension's own acceptance.spec.ts, which optimizes for functional coverage, not for looking good publicly). Deliberately stops at a local commit rather than pushing and opening a PR: `extctl publish approve` is the separate, explicit step that does that, so every submission (tags, minOCIS, screenshots) gets human review first, and `extctl publish retry-screenshots` can redo just the screenshots without restaging everything else. Screenshot capture reliability went through several real rounds of hardening this session, each traced to a genuine root cause rather than papered over with retries: - claude -p's headless first-turn handling could misread a long, structured prompt as reference context instead of a request — every extctl prompt now gets an explicit trailing task marker appended (claude.anchorPrompt). - A Docker Desktop/virtiofs bug breaks a file-mount stacked on a directory-mount when the underlying file doesn't exist yet, which it never does for most extensions on a fresh checkout (ensureExternalSitesManifest). - The capture path never ran `pnpm install`, so the playwright binary simply didn't exist on a fresh checkout. - A cached Playwright storageState survives independently of the oCIS instance that issued it — since capture always tears down and recreates oCIS, a stale cached token fails signature verification against the new instance's regenerated key, looking exactly like an auth flake (clearStaleAuthCache). - A failed test's screenshot (Playwright attaches one regardless of pass/fail) was being surfaced as a successful capture; now only passed results are ever collected. - The screenshot-writing Claude session now gets scoped Bash access (Bash(pnpm playwright test *) only) to actually run the spec it wrote against a live oCIS and fix real failures before returning, instead of writing blind — with a fresh-spec outer retry loop and a visually-degenerate-image check as further safety nets. See CLAUDE.md for the full command reference and the reasoning behind each of these fixes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
A cloned repo doesn't inherit its source's local git config — identity set via `git config` (without --global) lives in .git/config, which `git clone` doesn't copy. Four new tests cloned into a fresh checkout and then committed into it without setting an identity there, relying on a global git config to paper over it — worked on a dev machine with one configured, failed on CI runners that have none (same class of bug already hit and fixed once before for TestRebaseOntoOrigin's otherClone). Reproduced locally with HOME/GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM pointed away from any real config, matching a CI runner; all four now pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
extctl publish/publish approve/publish retry-screenshots: scans for web-extensions releases not yet inowncloud/marketplace, stages a submission per extension (bundle, resolved license/tags/minOCIS, dedicated Claude-generated screenshots) locally, then pushes + opens a PR only on explicitapprove— so tags/minOCIS/screenshots always get human review before anything goes public.acceptance.spec.ts), and the writing session now has scoped Bash access (Bash(pnpm playwright test *)only) to actually run its own spec against a live oCIS and fix real failures before returning, with a fresh-spec outer retry loop and a visually-degenerate-image check as safety nets.claude -pprompt-misreading issue fixed viaclaude.anchorPrompt, a Docker Desktop/virtiofs mount bug (ensureExternalSitesManifest), missingpnpm installin the capture path, a stale-auth-cache-vs-fresh-oCIS bug (clearStaleAuthCache), and failed tests' screenshots being surfaced as successful captures.Test plan
go build ./.../go vet ./.../go test ./...all cleanLukasHirt/appstore): staged and captured genuinely passing, good-quality screenshots forphoto-addon@0.1.0advanced-search@0.1.0end-to-end — PR opened successfully (feat(advanced-search): add 0.1.0 to the marketplace appstore#12).gitignore/staged diff excludes all local checkouts,runs/, and config before committing🤖 Generated with Claude Code