Skip to content

feat: add --screenshot option to slice add-variation and slice edit-variation#128

Merged
angeloashmore merged 6 commits intoaa/remote-modelingfrom
aa/screenshot-upload
Apr 14, 2026
Merged

feat: add --screenshot option to slice add-variation and slice edit-variation#128
angeloashmore merged 6 commits intoaa/remote-modelingfrom
aa/screenshot-upload

Conversation

@angeloashmore
Copy link
Copy Markdown
Member

@angeloashmore angeloashmore commented Apr 14, 2026

Resolves: #95

Description

Add a --screenshot option to slice add-variation and slice edit-variation that accepts either a local file path or a URL. The image is uploaded to S3 via the ACL provider, and the resulting imgix URL is stored in the variation's imageUrl field.

Checklist

  • A comprehensive Linear ticket, providing sufficient context and details to facilitate the review of the PR, is linked to the PR.
  • If my changes require tests, I added them.
  • If my changes affect backward compatibility, it has been discussed.
  • If my changes require an update to the CONTRIBUTING.md guide, I updated it.

Preview

How to QA 1

# With a URL
prismic slice edit-variation default --from-slice my_slice --screenshot https://example.com/image.png

# With a local file
prismic slice add-variation "With Image" --to my_slice --screenshot ./screenshot.png

Note

Medium Risk
Adds a new networked file-download + S3 upload flow (via ACL provider) to CLI commands, which can fail due to file type/protocol handling and external service interactions. Core slice update paths are unchanged but now conditionally include imageUrl updates.

Overview
Adds a new --screenshot/-s option to slice add-variation and slice edit-variation to set a variation’s imageUrl by uploading an image from a local path or HTTP(S) URL.

Introduces screenshot upload support in the custom-types client via the ACL provider (typed response validation, MIME-type allowlist, deterministic keying via MD5, and imgix URL generation) plus a new readURLFile() helper to load files from file:/http(s): URLs. Tests are extended to cover both URL-based and local-file screenshots for both commands.

Reviewed by Cursor Bugbot for commit be58488. Bugbot is set up for automated code reviews on this repo. Configure here.

Footnotes

  1. Please use these labels when submitting a review:
    ❓ #ask: Ask a question.
    💡 #idea: Suggest an idea.
    ⚠️ #issue: Strongly suggest a change.
    🎉 #nice: Share a compliment.

…dit-variation`

Upload a screenshot image (local file or URL) to Prismic's S3 via the
ACL provider, storing the resulting imgix URL in the variation's
`imageUrl` field.

Closes #95

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
angeloashmore and others added 4 commits April 14, 2026 20:26
- Use GET with auth headers (Authorization, Repository) for ACL provider
- Match response schema from slice-machine: { values: { url, fields }, imgixEndpoint }
- Support PRISMIC_HOST via getAclProviderUrl() helper
- Use request() instead of fetch() for S3 upload
- Fix buffer pooling issue by slicing to owned ArrayBuffer
- Build supported extensions list from MIME_TYPES
- Add local file path test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Separate file resolution (readURLFile) from upload logic so
uploadScreenshot only deals with Blobs. Add UnsupportedFileTypeError
for MIME type validation, fix getExtension edge case, and remove
dead imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 23ab3c3. Configure here.

Rename MIME_TYPE_EXTENSIONS to SUPPORTED_IMAGE_MIME_TYPES to clarify
intent. Use regex check for HTTP URLs instead of URL.canParse to avoid
misidentifying Windows absolute paths as URLs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@angeloashmore angeloashmore merged commit 40f71f0 into aa/remote-modeling Apr 14, 2026
13 checks passed
@angeloashmore angeloashmore deleted the aa/screenshot-upload branch April 14, 2026 23:32
angeloashmore added a commit that referenced this pull request Apr 15, 2026
…slices (#83)

* feat: add remote modeling commands for custom types, page types, and slices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: correct Custom Types API URLs and slice command messages

The insert/update endpoints were using incorrect paths (e.g. `customtypes`
instead of `customtypes/insert`), causing 401 errors on write operations.
Also fixes copy-paste errors in slice command output messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add e2e tests for custom-type, page-type, and slice commands

Covers create, list, view, remove for all three command groups, plus
slice-specific connect, disconnect, add-variation, and remove-variation.
All tests verify state against the Custom Types API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add default slice zone to page type and fix test types

Page types need a slice zone in Main tab by default. Replace `as any`
casts in slice connect/disconnect tests with proper types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add field management commands for remote modeling

Adds `field add`, `field list`, and `field remove` commands that operate
on custom types and slices via the Custom Types API, along with per-type
`field add <type>` subcommands for all supported field types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing primary field to test slice builder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add field edit command for remote modeling

Adds `prismic field edit` to modify existing field properties (label,
placeholder, type-specific options) on slices and custom types via the
API. Extracts shared `resolveFieldContainer` from `resolveModel` for
reuse across field-edit and field-remove.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: move sync logic into Adapter and sync after modeling commands

Consolidates sync logic (syncModels, syncSlices, syncCustomTypes) into
the Adapter class so all modeling commands can sync local files after
remote changes. This ensures local models stay up-to-date after any
create, remove, or field mutation command.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: replace syncModels with granular adapter methods

Move adapter sync into resolveModel/resolveFieldContainer so field
commands no longer depend on the adapter directly. Type/slice CRUD
commands now call specific adapter methods (create/update/delete)
instead of a full sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: unify `page-type` and `custom-type` into single `type` command (#104)

* feat: unify `page-type` and `custom-type` into single `type` command

Consolidates the separate `page-type` and `custom-type` top-level
commands into a single `type` command with a `--format` flag on create.

- `prismic type create <name> --format page` for page types
- `prismic type create <name>` defaults to custom format
- `prismic type list` shows all types with format in output
- `prismic type view/remove` work regardless of format
- Field targeting simplified: `--to-type`/`--from-type` replace
  `--to-page-type`/`--to-custom-type`/`--from-page-type`/`--from-custom-type`

Closes #96

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use "content type" in command descriptions for clarity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add `type edit` command (#106)

Closes #91

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add `slice edit` and `slice edit-variation` commands (#107)

* feat: add `slice edit` and `slice edit-variation` commands

Adds two new subcommands for editing slice and variation metadata after
creation. Also adds E2E tests for the recently added `type edit` command.

Closes #92

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add local fallback for `type edit` adapter call

Wraps adapter.updateCustomType in try/catch with createCustomType
fallback, matching the pattern used in other commands. Prevents crash
when the local customtypes/ directory doesn't contain the edited type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove --repeatable/--single flags from `type edit`

The Custom Types API does not support updating the repeatable property;
it must be changed from the writing room UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove --description from `slice edit-variation`

Edit commands should only expose options that the corresponding create
command exposes. `slice add-variation` does not accept --description.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add tab management commands (#108)

* feat: add `type add-tab`, `type edit-tab`, and `type remove-tab` commands

Adds tab management commands for content types:
- `add-tab` creates a new tab, optionally with a slice zone
- `edit-tab` renames a tab and/or adds/removes a slice zone
- `remove-tab` deletes a tab (guards against removing the last one)

Closes #94

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: validate mutually exclusive --with-slice-zone and --without-slice-zone flags

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: rename `--in` flag to `--from-slice`/`--from-type` (#110)

* refactor: rename `--in` flag to `--from-slice`/`--from-type`

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update tests to use renamed flags

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: show fields inline in `view` commands and remove `field list` (#111)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add `field view` command (#112)

* feat: add `field view` command

Add a command to inspect a single field's full configuration,
including label, placeholder, constraints, and type-specific settings.

Resolves #93

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: use compact buildSlice pattern in field-view tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: consolidate link-related field types (#114)

* feat: consolidate link-related field types

Merge `link-to-media` into `link` with a new `--allow` option that
accepts `document`, `media`, or `web`. Omitting `--allow` creates a
generic link. Keep `content-relationship` separate.

Update descriptions on `link` and `content-relationship` so agents
can tell when to use each one.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: validate --allow option and restore field-edit subtype guards

Validate that --allow is one of document, media, or web. Restore
subtype guards in field-edit so content-relationship fields can't
receive link-only options and vice versa.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: allow all Link options regardless of select value

Remove the select-based guard in field-edit so link fields with
select: "document" can still be edited with link-specific options
like --allow-target-blank and --allow-text.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: improve `content-relationship` help text (#115)

* feat: improve `content-relationship` help text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: drop FIELD CONSTRAINTS section from content-relationship help

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add a consistent table formatter for tabular output (#116)

* feat: add a consistent table formatter for tabular output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add header support to formatTable and add headers to list commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: avoid blank line in `preview list` when only simulator URL exists

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: rename preview list header from LABEL to NAME

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: replace name-based model specifiers with IDs (#117)

* feat: replace name-based model specifiers with IDs

Slice commands now resolve by `id` instead of `name`, content type
commands resolve by `id` instead of `label`, and variation commands
resolve by `id` instead of `name`.

Closes #105

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: rename `currentId` to `id` in slice-edit-variation

The "current" prefix was a holdover from name-based specifiers where
names could change. IDs are immutable, so the prefix is unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: add `getCustomType` and `getSlice` client functions (#124)

* refactor: add `getCustomType` and `getSlice` client functions

Replace the `getCustomTypes().find()` and `getSlices().find()` patterns
with dedicated single-resource fetch functions that set contextual error
messages on `NotFoundRequestError`. Add a central handler in the root
router to print those messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: give `NotFoundRequestError` a user-friendly default message

Overrides the raw "fetch failed: <url>" message with "Not found." so
unhandled 404s from any endpoint still produce a clean message when
caught by the root error handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: include URL in default NotFoundRequestError message

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add `--field` option to `field add content-relationship` and `field edit` (#123)

* feat: add `--field` option to `field add content-relationship` and `field edit`

Add a repeatable `--field` flag for specifying which fields to fetch from
related documents. Fields are validated against the production custom type
model via the Custom Types API.

Supports dot notation for nested selection:
- `--field title` for top-level fields
- `--field group.name` for group sub-fields
- `--field cr.name` for CR target type fields
- `--field group.cr.group.leaf` for full depth

Closes #103

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: use `getCustomType` instead of `getCustomTypes` + find

Replace 7 call sites that fetch all custom types just to find one by ID
with the single-type `GET /customtypes/{id}` endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: simplify field selection resolution with single recursive function

Replace 7 functions (157 lines) with a single recursive `resolveFields`
function and named `ResolvedField` type, reducing to 3 functions (107 lines).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unnatural phrasing from JSDoc comment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: simplify test custom type construction to use default fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: handle type removal when documents exist (#127)

Show a clear error message when attempting to remove a type that has
associated documents, guiding users to delete the documents first.

Closes #99

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add field reorder command (#129)

* feat: add field reorder command

Adds `prismic field reorder` to move a field before or after another
field. Supports cross-tab moves in custom types (destination tab is
determined by the anchor field) and dot-notation for group fields.

Resolves #100

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: simplify test model setup in field-reorder tests

Use buildSlice()/buildCustomType() with property assignment instead of
verbose override objects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add `--screenshot` option to `slice add-variation` and `slice edit-variation` (#128)

* feat: add `--screenshot` option to `slice add-variation` and `slice edit-variation`

Upload a screenshot image (local file or URL) to Prismic's S3 via the
ACL provider, storing the resulting imgix URL in the variation's
`imageUrl` field.

Closes #95

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback for screenshot upload

- Use GET with auth headers (Authorization, Repository) for ACL provider
- Match response schema from slice-machine: { values: { url, fields }, imgixEndpoint }
- Support PRISMIC_HOST via getAclProviderUrl() helper
- Use request() instead of fetch() for S3 upload
- Fix buffer pooling issue by slicing to owned ArrayBuffer
- Build supported extensions list from MIME_TYPES
- Add local file path test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: use response.blob() and URL for path construction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: accept Blob in uploadScreenshot and validate file type

Separate file resolution (readURLFile) from upload logic so
uploadScreenshot only deals with Blobs. Add UnsupportedFileTypeError
for MIME type validation, fix getExtension edge case, and remove
dead imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add local screenshot file test for slice edit-variation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback for screenshot upload

Rename MIME_TYPE_EXTENSIONS to SUPPORTED_IMAGE_MIME_TYPES to clarify
intent. Use regex check for HTTP URLs instead of URL.canParse to avoid
misidentifying Windows absolute paths as URLs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: misc fixes for remote modeling branch

- Remove unnecessary type parameters from request calls
- Fix field-edit to reference field.config instead of config
- Fix sync watch to generate types once after both syncs
- Use getCustomType in type-view instead of filtering list
- Fix error message to show variationId instead of variation object

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve nested field lookup and missing existence check

- Use root field ID for custom type tab lookup in resolveFieldContainer
  so dot-separated IDs (e.g. "my_group.subtitle") find the correct tab
- Add field existence check in field-edit to throw a clean CommandError
  instead of a TypeError when the field doesn't exist

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: join field IDs before fallback check in error message

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: allow adding placeholder to fields that lack one and remove unused --tab from SOURCE_OPTIONS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant