Skip to content

feat(slides):slide screenshot#1358

Merged
ethan-zhx merged 1 commit into
mainfrom
feat/slide_image
Jun 22, 2026
Merged

feat(slides):slide screenshot#1358
ethan-zhx merged 1 commit into
mainfrom
feat/slide_image

Conversation

@ethan-zhx

@ethan-zhx ethan-zhx commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a new slides +screenshot shortcut to fetch slide screenshots and save them as local image files instead of printing Base64 payloads to stdout.

What changed

  • Added slides +screenshot for existing slide pages:
    • supports --presentation
    • supports selecting slides by --slide-id or --slide-number
    • resolves wiki URLs to slides presentations when needed
  • Added render mode for raw slide XML:
    • supports --content @file / stdin
    • saves rendered output to local files
  • Writes screenshots into .lark-slides/screenshots by default
  • Suppresses Base64 image data in stdout and returns file metadata instead
  • Avoids overwriting existing files by deduplicating output names
  • Added shortcut docs and screenshot reference material
  • Added int_array flag parsing coverage needed by --slide-number
  • Registered slides:presentation:screenshot scope priority

Tests

  • Added unit tests covering:
    • scope declaration
    • file writing and Base64 suppression
    • slide-number requests
    • duplicate filename handling
    • required selector validation
    • content render flow
    • int_array flag parsing

Summary by CodeRabbit

  • New Features
    • Added slides +screenshot shortcut to generate local PNG/JPEG screenshots from either rendered slide XML (--content) or existing slides (--presentation with --slide-id/--slide-number), with Base64 suppressed in output.
    • Added support for int_array flags to allow repeated integer arguments (e.g., multi-page slide-number selection).
  • Bug Fixes / Improvements
    • Updated the screenshot capability recommendation scope.
  • Documentation
    • Added/expanded slides +screenshot quick reference and full command documentation.
  • Tests
    • Added tests for screenshot modes, validation, dry-run behavior, overwrite/deduplication, and int_array parsing.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces a new slides +screenshot shortcut that fetches server-rendered slide images as Base64, decodes them, and saves them locally. It supports list mode (--presentation + --slide-id/--slide-number) and render mode (--content XML). Adds int_array flag support, scope registration, file-safety and deduplication logic, comprehensive tests, and user documentation.

Changes

Slides Screenshot Feature

Layer / File(s) Summary
int_array flag type infrastructure
shortcuts/common/types.go, shortcuts/common/runner.go, shortcuts/common/runner_args_test.go
New int_array flag type enables repeated integer arguments (e.g., --slide-number 1 --slide-number 2,3). Includes type doc update, RuntimeContext.IntArray() accessor, cobra flag registration, and tests validating parsing.
Scope registration and shortcut wiring
internal/registry/scope_priorities.json, shortcuts/slides/shortcuts.go
New scope slides:presentation:screenshot added to registry with priority score 78.7030 and SlidesScreenshot shortcut registered in the slides shortcuts list.
Shortcut definition, validation, and mode routing
shortcuts/slides/slides_screenshot.go (lines 1–284)
Defines shortcut metadata and flags, implements Validate(), DryRun(), and Execute() with routing between render (--content) and list (--presentation + selectors), input normalization helpers, and output-dir safety probing via runtime.ResolveSavePath.
API response processing and safe file persistence
shortcuts/slides/slides_screenshot.go (lines 285–531)
Parses responses (list vs render JSON shapes), validates and decodes Base64 image data, maps format codes to file extensions, derives and sanitizes deterministic filename stems, writes files with collision-avoidance (up to 1000 candidates), and produces structured API/filesystem errors with summarized raw payloads including log_id from response headers.
Comprehensive test coverage
shortcuts/slides/slides_screenshot_test.go
Tests declared scopes, list-mode and render-mode behaviors, filename conventions and zero-padding, deduplication and overwrite-avoidance, flag validation errors, output-dir safety checks, dry-run messaging, and API error summarization with log_id propagation and server hints.
User documentation
skills/lark-slides/SKILL.md, skills/lark-slides/references/lark-slides-screenshot.md
Quick reference entry and full reference guide describing list vs render modes, parameters, output naming behavior with auto-suffix collision-avoidance, permission/whitelist notes, and usage examples for single-page, multi-page, slide-number-based, and XML render preview workflows.

Sequence Diagram

sequenceDiagram
  participant CLI
  participant SlidesScreenshot
  participant SlideImagesAPI
  participant SlideRenderAPI
  participant FileSystem
  CLI->>SlidesScreenshot: Execute with flags
  SlidesScreenshot->>SlidesScreenshot: Validate inputs
  alt Render mode (--content)
    SlidesScreenshot->>SlideRenderAPI: POST /slide_image/render (content)
    SlideRenderAPI-->>SlidesScreenshot: slide_image (base64 data)
  else List mode (--presentation)
    SlidesScreenshot->>SlideImagesAPI: POST /xml_presentation/.../slide_images (slide_ids/slide_numbers)
    SlideImagesAPI-->>SlidesScreenshot: slide_images[] (base64 array)
  end
  SlidesScreenshot->>FileSystem: Decode base64, write files (unique names)
  SlidesScreenshot-->>CLI: JSON metadata (no base64)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

domain/ccm

Suggested reviewers

  • fangshuyu-768
  • liangshuo-1

Poem

🐰 A rabbit hops through slides with glee,
Captures screenshots, one, two, three,
Base64 decoded, files placed neat,
Deduped names so runs repeat,
CLI brightens slides—a photo treat! 📸

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(slides):slide screenshot' directly corresponds to the main change—adding a new slides screenshot shortcut feature.
Description check ✅ Passed The PR description comprehensively covers Summary, What changed, and Tests sections matching the template structure with detailed implementation details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/slide_image

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@3f3e8ac4a356eab8221349df54102eddcefbb299

🧩 Skill update

npx skills add larksuite/cli#feat/slide_image -y -g

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (1)
shortcuts/slides/slides_screenshot.go (1)

406-422: ⚖️ Poor tradeoff

Avoid hand-building API error envelopes.

Per coding guidelines: "Use runtime.CallAPITyped (shortcuts) or errclass.BuildAPIError (raw responses) for Lark API errors — never hand-build error envelopes". While this handles malformed response data rather than initial API failures, consider using errclass.BuildAPIError or errs.NewInternalError(errs.SubtypeUnknown, ...).WithCause(err) for unclassified errors to maintain consistent error typing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/slides/slides_screenshot.go` around lines 406 - 422, The
slidesScreenshotAPIDataError function is hand-building an API error envelope;
replace this with the project's standardized error constructors (use
errclass.BuildAPIError for raw API-response style errors or
errs.NewInternalError(errs.SubtypeUnknown, "...").WithCause(err) for
unclassified/internal issues) so error typing stays consistent—update
slidesScreenshotAPIDataError to construct and return one of those standardized
error types (referencing slidesScreenshotAPIDataError,
summarizeScreenshotAPIData, and the ErrDetail fields currently used) and include
the same raw_data/log_id details as the cause or metadata on the returned error.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/slides/slides_screenshot_test.go`:
- Around line 402-418: Update TestSlidesScreenshotRejectsBadOutputDir to assert
typed error metadata using errs.ProblemOf instead of checking error message
substrings: call errs.ProblemOf(err) and verify the returned Problem's Category
and Subtype match the expected validation error and that Problem.Param equals
the flag name (e.g., "output-dir" or "--output-dir") for the runSlidesShortcut
invocation (SlidesScreenshot). Also assert cause preservation if applicable
(e.g., ErrInvalidPath) rather than relying on strings.Contains.
- Around line 342-357: Update TestSlidesScreenshotRenderRejectsListOnlyFlags to
assert typed error metadata using errs.ProblemOf instead of substring matching:
after runSlidesShortcut returns a non-nil err, call p := errs.ProblemOf(err) and
assert p != nil, then check p.Category, p.Subtype (the validation subtype for
presentation/content conflict) and p.Param equals the conflicting flag (e.g.,
"--presentation" or "--content") as appropriate; keep the existing
runSlidesShortcut and SlidesScreenshot references and preserve the existing
fatal checks when the problem metadata is missing or mismatched.
- Around line 238-252: The test TestSlidesScreenshotListRequiresSelector
currently asserts the missing-selector error by checking the error message
substring; update it to use errs.ProblemOf to assert the typed error metadata
instead: call errs.ProblemOf(err) (or equivalent helper) and assert the expected
Problem.Category, Problem.Subtype and Param (e.g., the selector param name) and
that the original cause is preserved for the error returned from
runSlidesShortcut when invoking SlidesScreenshot; replace the strings.Contains
check with these typed assertions while keeping the same runSlidesShortcut
invocation.
- Around line 325-340: In TestSlidesScreenshotRenderRejectsSlideSelectors
replace the substring-based assertion with a typed assertion using
errs.ProblemOf: call errs.ProblemOf(err, errs.Validation) (or the codebase's
Validation identifier) to get the problem, assert it's non-nil, then check the
problem's Subtype/Kind equals the validation subtype for conflicting arguments
(e.g. "conflicting-args" or the repo's specific subtype) and that the
problem.Param or Params include the "--content" parameter (and/or the slide
selector param like "--slide-id"/"--slide-number"); keep the existing error
generation by runSlidesShortcut and SlidesScreenshot but verify via
errs.ProblemOf rather than strings.Contains.
- Around line 420-470: The test must assert typed error metadata via
errs.ProblemOf for the underlying error; after obtaining exitErr, call
errs.ProblemOf on the underlying cause (e.g. errors.Unwrap(exitErr) or
exitErr.Cause) and assert the returned problem is non-nil and its Category and
Subtype match the expected values for the "no images" error (add these
assertions into TestSlidesScreenshotNoImagesErrorIncludesRawDataAndLogID near
where exitErr is inspected).

In `@shortcuts/slides/slides_screenshot.go`:
- Line 474: Replace the output.Errorf(...) calls used for local file I/O
failures in slides_screenshot.go (inside the function handling screenshots where
validate.SafeInputPath / SafeOutputPath is already used) with typed errors using
errs.NewInternalError(errs.SubtypeFileIO, "<context message>") and attach the
original error via .WithCause(err); update each occurrence (the shown return at
write screenshot, and the other instances at the lines noted) to return
errs.NewInternalError(errs.SubtypeFileIO, fmt.Sprintf("write screenshot %s: %v",
path, err)).WithCause(err) (or similar context-specific messages), and add the
import "github.com/larksuite/cli/pkg/errs" if missing.
- Line 285: The return uses output.Errorf for a local file I/O failure; replace
it with the typed error constructor errs.NewInternalError(errs.SubtypeFileIO,
...) (include the original error and a descriptive message like "create output
directory %s") and add the import "github.com/larksuite/cli/pkg/errs" if
missing; update the return in the function that creates the output directory
(the line returning output.Errorf(...)) to return the errs.NewInternalError(...)
instance instead.
- Line 19: Remove the import of github.com/larksuite/cli/internal/vfs and stop
calling vfs.MkdirAll and vfs.OpenFile; instead use runtime.FileIO() (the
fileio.FileIO instance) and its Save and Stat methods: replace any vfs.MkdirAll
usage with relying on fileIO.Save (which creates parent dirs) and replace
vfs.OpenFile(..., O_EXCL) patterns by implementing a no-overwrite flow that
checks file existence via fileIO.Stat and picks a unique filepath (e.g., append
a suffix or increment a counter) in a loop before calling fileIO.Save; add a
small helper (e.g., makeUniquePath or ensureUniqueSave) near the existing save
logic to encapsulate the Stat+unique-name loop, and remove all references to
vfs.OpenFile/vfs.MkdirAll in the functions that currently use them.

In `@skills/lark-slides/references/lark-slides-screenshot.md`:
- Around line 96-99: Replace the contradictory guidance that reads “不知道页面 ID,传
slide id 即可” with a clear instruction that if slide_id is unknown the user
should pass the slide index using the --slide-number option; update the text
mentioning slide_id to instead instruct using --slide-number (and optionally
give the expected numeric format) so the docs consistently direct users to use
--slide-number when slide_id is unavailable.

---

Nitpick comments:
In `@shortcuts/slides/slides_screenshot.go`:
- Around line 406-422: The slidesScreenshotAPIDataError function is
hand-building an API error envelope; replace this with the project's
standardized error constructors (use errclass.BuildAPIError for raw API-response
style errors or errs.NewInternalError(errs.SubtypeUnknown, "...").WithCause(err)
for unclassified/internal issues) so error typing stays consistent—update
slidesScreenshotAPIDataError to construct and return one of those standardized
error types (referencing slidesScreenshotAPIDataError,
summarizeScreenshotAPIData, and the ErrDetail fields currently used) and include
the same raw_data/log_id details as the cause or metadata on the returned error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3ec276fc-8760-4124-b78b-a897eb3abdc0

📥 Commits

Reviewing files that changed from the base of the PR and between eed711b and 0dda6f5.

📒 Files selected for processing (9)
  • internal/registry/scope_priorities.json
  • shortcuts/common/runner.go
  • shortcuts/common/runner_args_test.go
  • shortcuts/common/types.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_screenshot.go
  • shortcuts/slides/slides_screenshot_test.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-screenshot.md

Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot.go Outdated
Comment thread shortcuts/slides/slides_screenshot.go Outdated
Comment thread shortcuts/slides/slides_screenshot.go Outdated
Comment thread skills/lark-slides/references/lark-slides-screenshot.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/slides/slides_screenshot_test.go`:
- Around line 427-430: The file slides_screenshot_test.go has formatting issues
that do not comply with Go's standard formatting rules as enforced by gofmt. Run
the command gofmt -w shortcuts/slides/slides_screenshot_test.go to automatically
reformat the file to the correct standards, including the Headers map
initialization around line 427-430, and then verify the changes are correct
before committing.
- Around line 487-496: The test in the error handling section for the
slide-number API path (starting around the errs.ProblemOf call) currently only
asserts LogID and Hint fields, but is missing complete typed metadata
validation. Add assertions for Problem.Category and Problem.Subtype after the
existing LogID check. Additionally, since this appears to be a validation error,
use errors.As to extract the underlying errs.ValidationError type and assert the
Param field to verify the validation error includes the expected parameter
information. This ensures full typed metadata coverage and proper cause
preservation as per the coding guidelines.

In `@shortcuts/slides/slides_screenshot.go`:
- Around line 400-404: In the slidesScreenshotImageDataCauseError function,
replace the direct type assertion `if apiErr, ok := err.(*errs.APIError); ok`
with the errors.As pattern to properly handle wrapped errors. Use errors.As to
unwrap the error and check if it contains an *errs.APIError type, which will
correctly handle cases where the error is wrapped and will pass the errorlint
validation.
- Around line 425-428: The error handling for the runtime.DoAPI call is
incorrectly wrapping all errors as internal errors, which downgrade typed errors
and misclassify network failures. Instead of using errs.WrapInternal(err) for
the error returned from runtime.DoAPI, check if the error is already a typed
error and preserve it; for actual network/transport failures, use
errs.NewNetworkError(errs.SubtypeNetworkTransport, ...) to properly classify
them as network errors rather than internal errors. This ensures lower-layer
typed errors pass through unchanged and transport failures are correctly
categorized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b92c4c29-92cc-4a9b-bee2-befbea09eab1

📥 Commits

Reviewing files that changed from the base of the PR and between cfc1dfc and fd15a95.

📒 Files selected for processing (9)
  • internal/registry/scope_priorities.json
  • shortcuts/common/runner.go
  • shortcuts/common/runner_args_test.go
  • shortcuts/common/types.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_screenshot.go
  • shortcuts/slides/slides_screenshot_test.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-screenshot.md
✅ Files skipped from review due to trivial changes (5)
  • shortcuts/slides/shortcuts.go
  • shortcuts/common/types.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-screenshot.md
  • internal/registry/scope_priorities.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/common/runner_args_test.go

Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot_test.go
Comment thread shortcuts/slides/slides_screenshot.go
Comment thread shortcuts/slides/slides_screenshot.go
@ethan-zhx ethan-zhx force-pushed the feat/slide_image branch 2 times, most recently from 6626491 to d946e23 Compare June 18, 2026 08:50
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.64773% with 135 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.80%. Comparing base (1f2164c) to head (3f3e8ac).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/slides/slides_screenshot.go 61.27% 87 Missing and 47 partials ⚠️
shortcuts/slides/shortcuts.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1358      +/-   ##
==========================================
+ Coverage   73.72%   73.80%   +0.07%     
==========================================
  Files         781      787       +6     
  Lines       74217    76142    +1925     
==========================================
+ Hits        54717    56193    +1476     
- Misses      15437    15741     +304     
- Partials     4063     4208     +145     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread shortcuts/slides/slides_screenshot.go
Comment thread skills/lark-slides/references/lark-slides-screenshot.md Outdated
Comment thread shortcuts/slides/slides_screenshot.go Outdated
fangshuyu-768
fangshuyu-768 previously approved these changes Jun 18, 2026
@github-actions

Copy link
Copy Markdown

PR Quality Summary

The semantic review system could not produce a fully trusted result. This is not reported as a code defect.

System status

  • semantic review degraded: model retry stopped (endpoint=https[:]//ark.cn-beijing.volces.com/api/plan/v3/chat/completions model=deepseek-v4-pro response_format=none attempt=3/3 timeout=3m0s): context deadline exceeded — Action: inspect deterministic quality-gate diagnostics

@ethan-zhx ethan-zhx merged commit 9d4ae94 into main Jun 22, 2026
23 checks passed
@ethan-zhx ethan-zhx deleted the feat/slide_image branch June 22, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants