Skip to content

feat(slides): add +add-slide and +delete-slide shortcuts - #2120

Open
R0bynZhu wants to merge 1 commit into
mainfrom
feat/slides-slide-add-delete-shortcuts
Open

feat(slides): add +add-slide and +delete-slide shortcuts#2120
R0bynZhu wants to merge 1 commit into
mainfrom
feat/slides-slide-add-delete-shortcuts

Conversation

@R0bynZhu

@R0bynZhu R0bynZhu commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Add two single-page slide shortcuts on top of the raw xml_presentation.slide create/delete APIs.

slides +add-slide appends or inserts one page into an existing presentation. It accepts --presentation as a token, a /slides/ URL or a /wiki/ URL (resolved via wiki.spaces.get_node and checked for obj_type=slides), takes the page XML through --slide as a literal, @file or stdin so the document never has to be escaped into JSON and then into the shell, and auto-uploads placeholders, replacing them with the returned file_token. Omitting --before-slide-id appends to the end; the field is dropped from the body rather than sent empty, which the backend rejects as an unknown slide.

slides +delete-slide removes one page by slide_id with the same --presentation resolution. It is deliberately Risk "write" rather than the raw command's high-risk-write, so it does not require --yes: it targets a single explicit page and the deck keeps its version history.

Both take one page at a time so that batching stays an explicit loop and every call has an unambiguous outcome.

The image placeholder validation used by +create is extracted into a shared helper so both commands fail before any API call when a referenced file is missing, is not a regular file or exceeds the 20 MB upload limit.

Covered by unit tests and by dry-run e2e tests through the built binary, which is the only layer that proves a full document survives flag parsing intact. Reference docs are added for both commands and the existing slides skill docs now route to them.

Summary by CodeRabbit

  • New Features
    • Added slides +add-slide to append/insert a single <slide> with --before-slide-id, and image placeholders (<img src="@...">) automatically validated and uploaded with tokens substituted.
    • Added slides +delete-slide to delete one slide by slide_id, supporting token, /slides/ URLs, and /wiki/ URLs (with dry-run planning).
  • Bug Fixes
    • Improved fail-fast validation for @ image placeholder paths (missing/unsafe/non-regular/size limit) and clearer --slide/--file-scoped error details, including retry progress hints.
  • Documentation
    • Updated Slides guides/references to prefer +add-slide/+delete-slide and refreshed placeholder guidance.
  • Tests
    • Expanded unit and CLI E2E coverage for dry-run ordering, request parameters, wiki resolution, and error cases.

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

coderabbitai Bot commented Jul 30, 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

Adds slides +add-slide and slides +delete-slide, registers them, validates local image placeholders, supports wiki presentation resolution, updates +create --slides, and adds unit, E2E, coverage, and workflow documentation.

Changes

Slides page management

Layer / File(s) Summary
Add-slide contract and validation
shortcuts/slides/helpers.go, shortcuts/slides/slides_create.go, shortcuts/slides/slides_add_slide.go, shortcuts/slides/slides_add_slide_test.go
Defines add-slide flags, scopes, XML validation, placeholder-file checks, shared request shaping, and validation coverage.
Add-slide execution and coverage
shortcuts/slides/slides_add_slide.go, shortcuts/slides/slides_add_slide_test.go
Resolves wiki presentations, plans uploads, rewrites image tokens, creates slides, propagates response fields, and tests partial failures.
Delete-slide flow and coverage
shortcuts/slides/slides_delete_slide.go, shortcuts/slides/slides_delete_slide_test.go
Adds single-slide deletion with revision and tenant parameters, wiki resolution, dry-run planning, typed responses, and validation tests.
Typed file errors and shared test helpers
shortcuts/slides/slides_errors.go, shortcuts/slides/slides_media_upload.go, shortcuts/slides/helpers_test.go, shortcuts/slides/slides_errors_test.go
Classifies stat failures, preserves causes, updates error context, and adds reusable validation and dry-run assertions.
Shortcut registration and end-to-end workflows
shortcuts/slides/shortcuts.go, tests/cli_e2e/slides/*
Registers both shortcuts and covers dry-run traces, live append/insertion/deletion, readback ordering, and coverage reporting.
Slides workflow documentation
skills/lark-slides/**
Documents page management commands, image placeholders, creation guidance, wiki handling, native API boundaries, and deletion guidance.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: domain/ccm, feature

Suggested reviewers: liangshuo-1

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant WikiAPI
  participant MediaAPI
  participant SlidesAPI
  CLI->>WikiAPI: resolve --presentation wiki URL
  CLI->>MediaAPI: upload @ image placeholders
  CLI->>SlidesAPI: POST rewritten slide XML
  SlidesAPI-->>CLI: return slide_id and result fields
Loading
sequenceDiagram
  participant CLI
  participant WikiAPI
  participant SlidesAPI
  CLI->>WikiAPI: resolve --presentation wiki URL
  CLI->>SlidesAPI: DELETE slide with slide_id and revision_id
  SlidesAPI-->>CLI: return deleted result
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is on-topic, but it does not follow the required template sections for Summary, Changes, Test Plan, and Related Issues. Rewrite the PR description using the repository template and add the missing Summary, Changes, Test Plan, and Related Issues sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 78.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding the two new slide shortcuts.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/slides-slide-add-delete-shortcuts

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.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@735e988e991657b4e1dfd1be781d7aede4a28719

🧩 Skill update

npx skills add larksuite/cli#feat/slides-slide-add-delete-shortcuts -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: 5

🤖 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/helpers.go`:
- Around line 166-172: Update validateImagePlaceholderFiles to distinguish
missing files from permission or other Stat failures before calling
slidesInputStatError. Use the existing path/error classification to apply “file
not found” only when the path truly does not exist; pass a generic stat-failure
message for other errors while preserving the underlying error details.

In `@shortcuts/slides/slides_add_slide_test.go`:
- Around line 205-281: Update TestAddSlideRejectsNonSlideRoot,
TestAddSlideRejectsEmptySlide, and TestAddSlideMissingImageFailsBeforeAnyCall to
inspect typed metadata through errs.ProblemOf, asserting the expected category,
subtype, and --slide parameter. Replace the message-only error checks with
cause-preservation assertions: verify the non-slide-root validation retains its
underlying cause and the missing-image error wraps the underlying Stat failure;
retain only message checks needed for behavior not represented by typed
metadata.

In `@shortcuts/slides/slides_delete_slide_test.go`:
- Around line 143-146: Update the error-path assertions in the slide deletion
tests, including the additional indicated case, to verify expected Category and
Subtype through errs.ProblemOf while retaining errors.As for
ValidationError.Param. Keep the existing parameter checks and message
assertions, adding typed metadata validation without reading Param from
errs.ProblemOf.

In `@skills/lark-slides/references/xml-schema-quick-ref.md`:
- Around line 235-240: Update the nearby img example’s `src` placeholder from
`file_token_or_url` to a name representing the supported file token or
local-path placeholder, removing any implication that external URLs are valid
while preserving the surrounding XML example.

In `@tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go`:
- Around line 21-149: The existing TestSlidesAddSlideDryRunE2E and
TestSlidesDeleteSlideDryRunE2E tests cover only request generation; add a
credential-backed live E2E test that creates a presentation, adds a slide,
verifies the slide through the API, deletes it, and cleans up the created
presentation. Reuse the existing slides E2E helpers and ensure cleanup runs even
when an assertion or intermediate API call fails.
🪄 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 Plus

Run ID: 3d4302de-6ccf-42ff-90d0-21b76b7452a1

📥 Commits

Reviewing files that changed from the base of the PR and between 4a16139 and 333b542.

📒 Files selected for processing (18)
  • shortcuts/slides/helpers.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_add_slide.go
  • shortcuts/slides/slides_add_slide_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_delete_slide.go
  • shortcuts/slides/slides_delete_slide_test.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-add-slide.md
  • skills/lark-slides/references/lark-slides-create.md
  • skills/lark-slides/references/lark-slides-delete-slide.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md
  • skills/lark-slides/references/troubleshooting.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • tests/cli_e2e/slides/coverage.md
  • tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go
💤 Files with no reviewable changes (1)
  • skills/lark-slides/references/troubleshooting.md

Comment thread shortcuts/slides/helpers.go
Comment thread shortcuts/slides/slides_add_slide_test.go
Comment on lines +143 to +146
var ve *errs.ValidationError
if !errors.As(err, &ve) || ve.Param != "--slide-id" {
t.Fatalf("want *errs.ValidationError on --slide-id, got %v", err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert typed metadata for error paths.

These tests only check a concrete type/param or message text. Assert the expected Category and Subtype with errs.ProblemOf; retain errors.As for ValidationError.Param.

As per coding guidelines, error-path tests must assert typed metadata. Based on learnings, errs.ProblemOf does not expose Param; read it through errors.As.

Also applies to: 209-214

🤖 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_delete_slide_test.go` around lines 143 - 146, Update
the error-path assertions in the slide deletion tests, including the additional
indicated case, to verify expected Category and Subtype through errs.ProblemOf
while retaining errors.As for ValidationError.Param. Keep the existing parameter
checks and message assertions, adding typed metadata validation without reading
Param from errs.ProblemOf.

Sources: Coding guidelines, Learnings

Comment thread skills/lark-slides/references/xml-schema-quick-ref.md
Comment on lines +21 to +149
func TestSlidesAddSlideDryRunE2E(t *testing.T) {
setSlidesDryRunEnv(t)

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
t.Cleanup(cancel)

const slideXML = `<slide xmlns="http://www.larkoffice.com/sml/2.0"><data></data></slide>`

tests := []struct {
name string
args []string
assertion func(t *testing.T, stdout string)
}{
{
name: "append to end",
args: []string{
"slides", "+add-slide",
"--presentation", "presAddDryRun",
"--slide", slideXML,
"--dry-run",
},
assertion: func(t *testing.T, stdout string) {
require.Equal(t, slideXML, gjson.Get(stdout, "data.api.0.body.slide.content").String(), stdout)
// Appending is expressed by omitting before_slide_id: an empty
// string is rejected by the backend as an unknown slide.
require.False(t, gjson.Get(stdout, "data.api.0.body.before_slide_id").Exists(), stdout)
require.Equal(t, int64(-1), gjson.Get(stdout, "data.api.0.params.revision_id").Int(), stdout)
require.False(t, gjson.Get(stdout, "data.api.0.params.tid").Exists(), stdout)
require.Equal(t, int64(0), gjson.Get(stdout, "data.images_to_upload").Int(), stdout)
},
},
{
name: "insert before a page with locking",
args: []string{
"slides", "+add-slide",
"--presentation", "presAddDryRun",
"--slide", slideXML,
"--before-slide-id", "slide_target",
"--revision-id", "12",
"--tid", "tx_e2e",
"--dry-run",
},
assertion: func(t *testing.T, stdout string) {
require.Equal(t, "slide_target", gjson.Get(stdout, "data.api.0.body.before_slide_id").String(), stdout)
require.Equal(t, int64(12), gjson.Get(stdout, "data.api.0.params.revision_id").Int(), stdout)
require.Equal(t, "tx_e2e", gjson.Get(stdout, "data.api.0.params.tid").String(), stdout)
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: tt.args,
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)

require.Equal(t, "POST", gjson.Get(result.Stdout, "data.api.0.method").String(), result.Stdout)
require.Equal(t,
"/open-apis/slides_ai/v1/xml_presentations/presAddDryRun/slide",
gjson.Get(result.Stdout, "data.api.0.url").String(),
result.Stdout,
)
tt.assertion(t, result.Stdout)
})
}
}

// TestSlidesDeleteSlideDryRunE2E covers the delete request shape and, more
// importantly, pins that the shortcut runs without --yes. The raw
// xml_presentation.slide.delete command is high-risk-write and would exit 10
// with confirmation_required here; the shortcut is Risk "write" on purpose.
func TestSlidesDeleteSlideDryRunE2E(t *testing.T) {
setSlidesDryRunEnv(t)

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
t.Cleanup(cancel)

result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{
"slides", "+delete-slide",
"--presentation", "presDeleteDryRun",
"--slide-id", "slide_gone",
"--tid", "tx_e2e",
"--dry-run",
},
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)

require.Equal(t, "DELETE", gjson.Get(result.Stdout, "data.api.0.method").String(), result.Stdout)
require.Equal(t,
"/open-apis/slides_ai/v1/xml_presentations/presDeleteDryRun/slide",
gjson.Get(result.Stdout, "data.api.0.url").String(),
result.Stdout,
)
require.Equal(t, "slide_gone", gjson.Get(result.Stdout, "data.api.0.params.slide_id").String(), result.Stdout)
require.Equal(t, int64(-1), gjson.Get(result.Stdout, "data.api.0.params.revision_id").Int(), result.Stdout)
require.Equal(t, "tx_e2e", gjson.Get(result.Stdout, "data.api.0.params.tid").String(), result.Stdout)
}

// TestSlidesDeleteSlideWikiDryRunE2E proves the wiki URL is resolved as a
// declared first step instead of being sent to the slides API as a token.
func TestSlidesDeleteSlideWikiDryRunE2E(t *testing.T) {
setSlidesDryRunEnv(t)

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
t.Cleanup(cancel)

result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{
"slides", "+delete-slide",
"--presentation", "https://example.feishu.cn/wiki/wikcnE2ETOKEN",
"--slide-id", "slide_gone",
"--dry-run",
},
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)

require.Equal(t, "GET", gjson.Get(result.Stdout, "data.api.0.method").String(), result.Stdout)
require.Equal(t, "/open-apis/wiki/v2/spaces/get_node", gjson.Get(result.Stdout, "data.api.0.url").String(), result.Stdout)
require.Equal(t, "wikcnE2ETOKEN", gjson.Get(result.Stdout, "data.api.0.params.token").String(), result.Stdout)
require.Equal(t, "DELETE", gjson.Get(result.Stdout, "data.api.1.method").String(), result.Stdout)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Add a live add/delete workflow test.

These dry-run tests do not exercise the write endpoints. Add a credential-backed, self-contained create → add → verify → delete → cleanup flow so the new destructive behavior is validated against the API.

As per coding guidelines, new flows under tests/cli_e2e/ require live E2E coverage with create/use/cleanup.

🤖 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 `@tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go` around lines 21
- 149, The existing TestSlidesAddSlideDryRunE2E and
TestSlidesDeleteSlideDryRunE2E tests cover only request generation; add a
credential-backed live E2E test that creates a presentation, adds a slide,
verifies the slide through the API, deletes it, and cleans up the created
presentation. Reuse the existing slides E2E helpers and ensure cleanup runs even
when an assertion or intermediate API call fails.

Source: Coding guidelines

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.55556% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.43%. Comparing base (1f565a2) to head (735e988).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/slides/slides_add_slide.go 88.23% 7 Missing and 7 partials ⚠️
shortcuts/slides/slides_delete_slide.go 87.34% 5 Missing and 5 partials ⚠️
shortcuts/slides/helpers.go 75.00% 2 Missing and 1 partial ⚠️
shortcuts/slides/slides_create.go 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2120      +/-   ##
==========================================
+ Coverage   75.19%   75.43%   +0.24%     
==========================================
  Files         914      926      +12     
  Lines       96789    98214    +1425     
==========================================
+ Hits        72778    74087    +1309     
- Misses      18413    18485      +72     
- Partials     5598     5642      +44     

☔ 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.

@R0bynZhu
R0bynZhu force-pushed the feat/slides-slide-add-delete-shortcuts branch from 333b542 to 8e2ee4c Compare July 30, 2026 13:21

@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/helpers_test.go`:
- Around line 426-448: Update assertValidationProblem to accept an expected
error instead of the boolean wantCause, and assert that the wrapped cause
matches it using errors.Is. Adjust every call site to pass the relevant sentinel
or expected error, such as fs.ErrNotExist, while preserving the existing typed
metadata assertions.

In `@shortcuts/slides/slides_delete_slide.go`:
- Around line 146-163: Update deleteSlideID and deleteSlideQuery to preserve raw
user-supplied slide-id and tid values in requests. Use a trimmed slide-id only
for the empty-value validation, return the original runtime.Str("slide-id"), and
check tid for emptiness without trimming the value stored in query["tid"].

In `@skills/lark-slides/references/lark-slides-create.md`:
- Around line 15-16: Resolve the conflicting complex-XML guidance in the
creation workflow: make the `jq --rawfile` example explicitly apply only to
intentional one-step `+create --slides` usage, while preserving the two-step
`+create` followed by `+add-slide` recommendation for complex XML. Update the
relevant guidance near the `+create --slides` example without changing the
existing append/insert behavior.

In `@skills/lark-slides/SKILL.md`:
- Line 108: Update the pre-submission workflow around the CRITICAL XML
submission requirement so only xml_text_overlap_lint.py runs before invoking
slides +create, slides +add-slide, xml_presentation.slide create, or slides
+replace-pages; retain the requirement that summary.error_count is 0. Move
warning-related screenshot verification to after creation or update the existing
post-creation workflow to require screenshots and readback there, unless a
documented local renderer is provided for pre-submit verification.
🪄 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 Plus

Run ID: 7231638e-31d3-4170-8065-36ee51073555

📥 Commits

Reviewing files that changed from the base of the PR and between 333b542 and 8e2ee4c.

📒 Files selected for processing (22)
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_add_slide.go
  • shortcuts/slides/slides_add_slide_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_delete_slide.go
  • shortcuts/slides/slides_delete_slide_test.go
  • shortcuts/slides/slides_errors.go
  • shortcuts/slides/slides_errors_test.go
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-add-slide.md
  • skills/lark-slides/references/lark-slides-create.md
  • skills/lark-slides/references/lark-slides-delete-slide.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md
  • skills/lark-slides/references/troubleshooting.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • tests/cli_e2e/slides/coverage.md
  • tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go
💤 Files with no reviewable changes (1)
  • skills/lark-slides/references/troubleshooting.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/xml-schema-quick-ref.md

Comment thread shortcuts/slides/helpers_test.go Outdated
Comment on lines +146 to +163
func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
id := strings.TrimSpace(runtime.Str("slide-id"))
if id == "" {
return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
}
return id, nil
}

// deleteSlideQuery builds the query params shared by dry-run and execute.
func deleteSlideQuery(runtime *common.RuntimeContext, slideID string) map[string]interface{} {
query := map[string]interface{}{
"slide_id": slideID,
"revision_id": runtime.Int("revision-id"),
}
if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
query["tid"] = tid
}
return query

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not silently normalize opaque identifiers.

Trimming --slide-id or --tid changes user-supplied values; " slide_123 " can delete slide_123 rather than fail or be sent faithfully. Use trimming only to detect an empty slide-id, then retain the raw values in the request.

Proposed fix
 func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
-	id := strings.TrimSpace(runtime.Str("slide-id"))
-	if id == "" {
+	id := runtime.Str("slide-id")
+	if strings.TrimSpace(id) == "" {
 		return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
 	}
 	return id, nil
 }
@@
-	if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
+	if tid := runtime.Str("tid"); tid != "" {
 		query["tid"] = tid
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
id := strings.TrimSpace(runtime.Str("slide-id"))
if id == "" {
return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
}
return id, nil
}
// deleteSlideQuery builds the query params shared by dry-run and execute.
func deleteSlideQuery(runtime *common.RuntimeContext, slideID string) map[string]interface{} {
query := map[string]interface{}{
"slide_id": slideID,
"revision_id": runtime.Int("revision-id"),
}
if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
query["tid"] = tid
}
return query
func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
id := runtime.Str("slide-id")
if strings.TrimSpace(id) == "" {
return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
}
return id, nil
}
// deleteSlideQuery builds the query params shared by dry-run and execute.
func deleteSlideQuery(runtime *common.RuntimeContext, slideID string) map[string]interface{} {
query := map[string]interface{}{
"slide_id": slideID,
"revision_id": runtime.Int("revision-id"),
}
if tid := runtime.Str("tid"); tid != "" {
query["tid"] = tid
}
return query
}
🤖 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_delete_slide.go` around lines 146 - 163, Update
deleteSlideID and deleteSlideQuery to preserve raw user-supplied slide-id and
tid values in requests. Use a trimmed slide-id only for the empty-value
validation, return the original runtime.Str("slide-id"), and check tid for
emptiness without trimming the value stored in query["tid"].

Source: Coding guidelines

Comment thread skills/lark-slides/references/lark-slides-create.md
Comment thread skills/lark-slides/SKILL.md Outdated
@R0bynZhu
R0bynZhu force-pushed the feat/slides-slide-add-delete-shortcuts branch from 8e2ee4c to 9a69581 Compare July 30, 2026 13:31

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shortcuts/slides/slides_create.go (1)

253-274: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

uploadSlidesPlaceholders hardcodes --slides as the typed Param, but it's now shared with +add-slide (flag --slide).

Lines 258 and 261 always attribute Stat/IsRegular failures to --slides. shortcuts/slides/slides_add_slide.go Execute calls this same function (line 169) for the --slide flag with no way to override the param. If a placeholder file is removed/altered between Validate and Execute (or any other reused caller emerges), the resulting ValidationError.Param will incorrectly read --slides for an +add-slide invocation — contradicting the explicit "agents route on the typed Param" design documented in slides_add_slide.go.

Thread the flag name through as a parameter instead of hardcoding it.

🐛 Proposed fix
-func uploadSlidesPlaceholders(runtime *common.RuntimeContext, presentationID string, paths []string) (map[string]string, int, error) {
+func uploadSlidesPlaceholders(runtime *common.RuntimeContext, param, presentationID string, paths []string) (map[string]string, int, error) {
 	tokens := make(map[string]string, len(paths))
 	for i, path := range paths {
 		stat, err := runtime.FileIO().Stat(path)
 		if err != nil {
-			return tokens, i, slidesInputStatError(err, "--slides", fmt.Sprintf("@%s", path))
+			return tokens, i, slidesInputStatError(err, param, fmt.Sprintf("@%s", path))
 		}
 		if !stat.Mode().IsRegular() {
-			return tokens, i, errs.NewValidationError(errs.SubtypeInvalidArgument, "@%s: must be a regular file", path).WithParam("--slides")
+			return tokens, i, errs.NewValidationError(errs.SubtypeInvalidArgument, "@%s: must be a regular file", path).WithParam(param)
 		}

And update both call sites: uploadSlidesPlaceholders(runtime, "--slides", presentationID, placeholders) in this file, uploadSlidesPlaceholders(runtime, "--slide", presentationID, placeholders) in shortcuts/slides/slides_add_slide.go.

🤖 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_create.go` around lines 253 - 274, Update
uploadSlidesPlaceholders to accept the flag name as a parameter and use it when
creating Stat and regular-file ValidationErrors instead of hardcoding
"--slides". Pass "--slides" from its existing caller and "--slide" from the
+add-slide caller in Execute, preserving the existing validation behavior and
typed Param attribution.
♻️ Duplicate comments (1)
shortcuts/slides/slides_delete_slide.go (1)

146-164: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trimming mutates the transmitted slide-id/tid instead of just validating emptiness.

id := strings.TrimSpace(runtime.Str("slide-id")) (Line 147) and tid := strings.TrimSpace(runtime.Str("tid")) (Line 160) both use the trimmed value in the request, not just to detect blankness. " slide_123 " would delete slide_123 rather than failing or being sent verbatim.

🐛 Proposed fix to preserve raw values
 func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
-	id := strings.TrimSpace(runtime.Str("slide-id"))
-	if id == "" {
+	id := runtime.Str("slide-id")
+	if strings.TrimSpace(id) == "" {
 		return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
 	}
 	return id, nil
 }
@@
-	if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
+	if tid := runtime.Str("tid"); strings.TrimSpace(tid) != "" {
 		query["tid"] = tid
 	}

As per coding guidelines, "never silently coerce unsupported inputs, ignore unhonored options, default missing identities, or discard writes."

🤖 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_delete_slide.go` around lines 146 - 164, Update
deleteSlideID and deleteSlideQuery to preserve the raw slide-id and tid values
in the transmitted request while still rejecting a slide-id that is empty after
trimming. Use trimmed values only for emptiness validation, return the original
runtime.Str("slide-id"), and add tid based on validation without replacing its
raw value.

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_delete_slide_test.go`:
- Around line 142-143: Update the validation-error assertions at both call sites
of assertValidationProblem in the slide deletion tests to inspect errs.ProblemOf
metadata, explicitly verifying the expected Category, Subtype, and "--slide-id"
parameter, while also asserting the original cause is preserved. If
assertValidationProblem does not provide these checks, extend or replace it so
every affected test performs the required typed metadata and cause assertions.

In `@tests/cli_e2e/slides/slides_slide_add_delete_workflow_test.go`:
- Around line 121-124: Ensure each ordering assertion in the slide add/delete
workflow first verifies both compared body markers with require.Contains. Update
the assertions around bodyFirst/bodyAppended and the analogous later comparison
so strings.Index is only evaluated after both substrings are confirmed present,
preserving the existing ordering checks.

---

Outside diff comments:
In `@shortcuts/slides/slides_create.go`:
- Around line 253-274: Update uploadSlidesPlaceholders to accept the flag name
as a parameter and use it when creating Stat and regular-file ValidationErrors
instead of hardcoding "--slides". Pass "--slides" from its existing caller and
"--slide" from the +add-slide caller in Execute, preserving the existing
validation behavior and typed Param attribution.

---

Duplicate comments:
In `@shortcuts/slides/slides_delete_slide.go`:
- Around line 146-164: Update deleteSlideID and deleteSlideQuery to preserve the
raw slide-id and tid values in the transmitted request while still rejecting a
slide-id that is empty after trimming. Use trimmed values only for emptiness
validation, return the original runtime.Str("slide-id"), and add tid based on
validation without replacing its raw value.
🪄 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 Plus

Run ID: 4238c143-0c99-402e-a435-3c07182d04c2

📥 Commits

Reviewing files that changed from the base of the PR and between 8e2ee4c and 9a69581.

📒 Files selected for processing (23)
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_add_slide.go
  • shortcuts/slides/slides_add_slide_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_delete_slide.go
  • shortcuts/slides/slides_delete_slide_test.go
  • shortcuts/slides/slides_errors.go
  • shortcuts/slides/slides_errors_test.go
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-add-slide.md
  • skills/lark-slides/references/lark-slides-create.md
  • skills/lark-slides/references/lark-slides-delete-slide.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md
  • skills/lark-slides/references/troubleshooting.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • tests/cli_e2e/slides/coverage.md
  • tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go
  • tests/cli_e2e/slides/slides_slide_add_delete_workflow_test.go
💤 Files with no reviewable changes (1)
  • skills/lark-slides/references/troubleshooting.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • tests/cli_e2e/slides/coverage.md

Comment on lines +142 to +143
assertValidationProblem(t, err, "--slide-id", false)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Confirm assertValidationProblem asserts typed Category/Subtype, not just Param.

Per coding guidelines, error-path tests must assert errs.ProblemOf metadata (category, subtype, param) and cause preservation, not just param/message. assertValidationProblem is not defined in this file, so its coverage of Category/Subtype can't be confirmed from the given context. This mirrors a past review comment raised on this exact call site.

Also applies to: 209-214.

#!/bin/bash
# Locate assertValidationProblem's definition to confirm it checks Category/Subtype via errs.ProblemOf.
rg -n -A 20 'func assertValidationProblem' --type=go
🤖 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_delete_slide_test.go` around lines 142 - 143, Update
the validation-error assertions at both call sites of assertValidationProblem in
the slide deletion tests to inspect errs.ProblemOf metadata, explicitly
verifying the expected Category, Subtype, and "--slide-id" parameter, while also
asserting the original cause is preserved. If assertValidationProblem does not
provide these checks, extend or replace it so every affected test performs the
required typed metadata and cause assertions.

Source: Coding guidelines

Comment thread tests/cli_e2e/slides/slides_slide_add_delete_workflow_test.go
@R0bynZhu
R0bynZhu force-pushed the feat/slides-slide-add-delete-shortcuts branch from 9a69581 to b31c209 Compare July 30, 2026 13:53

@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: 1

♻️ Duplicate comments (1)
shortcuts/slides/slides_delete_slide.go (1)

146-164: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don't silently trim opaque --slide-id / --tid values before sending them.

strings.TrimSpace is applied to the value stored/returned, not just to the emptiness check, so " slide_123 " silently becomes slide_123 in the outgoing DELETE request. As per coding guidelines, **/*.go code must "preserve values faithfully; never silently coerce unsupported inputs... Return a typed validation error when a requested behavior cannot be honored." Trim only for the blank check, keep the raw value in the request.

🐛 Proposed fix
 func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
-	id := strings.TrimSpace(runtime.Str("slide-id"))
-	if id == "" {
+	id := runtime.Str("slide-id")
+	if strings.TrimSpace(id) == "" {
 		return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
 	}
 	return id, nil
 }
@@
-	if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
+	if tid := runtime.Str("tid"); strings.TrimSpace(tid) != "" {
 		query["tid"] = tid
 	}
🤖 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_delete_slide.go` around lines 146 - 164, The
deleteSlideID and deleteSlideQuery helpers must preserve raw opaque --slide-id
and --tid values when constructing the DELETE request. Use trimmed copies only
to determine whether either input is blank, return the existing typed validation
error for an empty slide ID, and store the original untrimmed values in the
returned ID and query.

Source: Coding guidelines

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

187-194: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Rename the shared error enrichment helper to avoid replace-slide naming.

enrichSlidesReplaceError only attaches slides3350001Hint, but that constant is a replace-slide checklist about block_id, block_replace/block_insert, and insert_before_block_id; for +add-slide it can attach add-slide-specific content such as no page was added and image-upload failure details. Rename/relocate this helper and constants so add-slide failures cannot inherit replace-only troubleshooting text.

🤖 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_add_slide.go` around lines 187 - 194, The add-slide
error path must stop using the replace-slide-specific enrichSlidesReplaceError
helper and slides3350001Hint. Rename or relocate the shared enrichment logic and
constants, then provide add-slide-specific error enrichment covering “no page
was added” and image-upload failure details while keeping replace-slide
troubleshooting isolated to the replace flow; update the call site around the
placeholders handling accordingly.
🤖 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 `@skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md`:
- Around line 171-173: Update the command reference in the local-image upload
guidance to use the registered space-separated spelling “xml_presentation.slide
create” consistently, including any related wording that could be copied
directly. Preserve the existing upload sequence and shortcut references.

---

Duplicate comments:
In `@shortcuts/slides/slides_delete_slide.go`:
- Around line 146-164: The deleteSlideID and deleteSlideQuery helpers must
preserve raw opaque --slide-id and --tid values when constructing the DELETE
request. Use trimmed copies only to determine whether either input is blank,
return the existing typed validation error for an empty slide ID, and store the
original untrimmed values in the returned ID and query.

---

Nitpick comments:
In `@shortcuts/slides/slides_add_slide.go`:
- Around line 187-194: The add-slide error path must stop using the
replace-slide-specific enrichSlidesReplaceError helper and slides3350001Hint.
Rename or relocate the shared enrichment logic and constants, then provide
add-slide-specific error enrichment covering “no page was added” and
image-upload failure details while keeping replace-slide troubleshooting
isolated to the replace flow; update the call site around the placeholders
handling accordingly.
🪄 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 Plus

Run ID: 726669d1-444f-452c-b55a-6d480f520f6a

📥 Commits

Reviewing files that changed from the base of the PR and between 9a69581 and b31c209.

📒 Files selected for processing (23)
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_add_slide.go
  • shortcuts/slides/slides_add_slide_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_delete_slide.go
  • shortcuts/slides/slides_delete_slide_test.go
  • shortcuts/slides/slides_errors.go
  • shortcuts/slides/slides_errors_test.go
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-add-slide.md
  • skills/lark-slides/references/lark-slides-create.md
  • skills/lark-slides/references/lark-slides-delete-slide.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md
  • skills/lark-slides/references/troubleshooting.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • tests/cli_e2e/slides/coverage.md
  • tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go
  • tests/cli_e2e/slides/slides_slide_add_delete_workflow_test.go
💤 Files with no reviewable changes (1)
  • skills/lark-slides/references/troubleshooting.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • skills/lark-slides/references/lark-slides-media-upload.md
  • tests/cli_e2e/slides/coverage.md
  • skills/lark-slides/references/xml-schema-quick-ref.md

Comment on lines +171 to +173
> **本地图片必须先上传**:`xml_presentation.slide.create` 不识别 `@./local.png` 占位符,直接调本接口时必须先用 [`slides +media-upload`](lark-slides-media-upload.md) 拿到 `file_token`,再写进 `<img src="<file_token>">`。
>
> 如果是从零开始建带图 PPT,**强烈建议改用 [`slides +create --slides '[...]'`](lark-slides-create.md#本地图片path-占位符)** 一步搞定(自动上传 + 替换 token
> 占位符是 shortcut 的能力:给已有 PPT 加带图新页用 [`+add-slide`](lark-slides-add-slide.md),从零建带图 PPT 用 [`+create --slides`](lark-slides-create.md#本地图片path-占位符),都会自动上传并替换 token。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the registered command spelling consistently.

Line 171 writes xml_presentation.slide.create, but the documented command is xml_presentation.slide create. Change this to the space-separated command form or describe it as the native API operation to avoid copy/paste failures. Based on learnings, the registered command is the singular xml_presentation.slide create.

🤖 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 `@skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md`
around lines 171 - 173, Update the command reference in the local-image upload
guidance to use the registered space-separated spelling “xml_presentation.slide
create” consistently, including any related wording that could be copied
directly. Preserve the existing upload sequence and shortcut references.

Source: Learnings

Add two single-page slide shortcuts on top of the raw
xml_presentation.slide create/delete APIs.

slides +add-slide appends or inserts one page into an existing
presentation. It accepts --presentation as a token, a /slides/ URL or a
/wiki/ URL (resolved via wiki.spaces.get_node and checked for
obj_type=slides), takes the page XML through --slide as a literal, @file
or stdin so the document never has to be escaped into JSON and then into
the shell, and auto-uploads <img src="@./local.png"> placeholders,
replacing them with the returned file_token. Omitting --before-slide-id
appends to the end; the field is dropped from the body rather than sent
empty, which the backend rejects as an unknown slide.

slides +delete-slide removes one page by slide_id with the same
--presentation resolution. It is deliberately Risk "write" rather than
the raw command's high-risk-write, so it does not require --yes: it
targets a single explicit page and the deck keeps its version history.

Both take one page at a time so that batching stays an explicit loop and
every call has an unambiguous outcome.

The image placeholder validation used by +create is extracted into a
shared helper so both commands fail before any API call when a referenced
file is missing, is not a regular file or exceeds the 20 MB upload limit.

Covered by unit tests and by dry-run e2e tests through the built binary,
which is the only layer that proves a full <slide> document survives flag
parsing intact. Reference docs are added for both commands and the
existing slides skill docs now route to them.
@R0bynZhu
R0bynZhu force-pushed the feat/slides-slide-add-delete-shortcuts branch from b31c209 to 735e988 Compare July 30, 2026 14:09

@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: 2

♻️ Duplicate comments (1)
shortcuts/slides/slides_delete_slide.go (1)

146-164: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don't silently normalize opaque --slide-id/--tid values.

strings.TrimSpace on runtime.Str("slide-id")/runtime.Str("tid") mutates the value actually sent to the API. Use trimming only to detect emptiness, then send the raw flag value.

As per coding guidelines: "never silently coerce unsupported inputs, ignore unhonored options, default missing identities, or discard writes."

🐛 Proposed fix
 func deleteSlideID(runtime *common.RuntimeContext) (string, error) {
-	id := strings.TrimSpace(runtime.Str("slide-id"))
-	if id == "" {
+	id := runtime.Str("slide-id")
+	if strings.TrimSpace(id) == "" {
 		return "", errs.NewValidationError(errs.SubtypeInvalidArgument, "--slide-id cannot be empty").WithParam("--slide-id")
 	}
 	return id, nil
 }
@@
-	if tid := strings.TrimSpace(runtime.Str("tid")); tid != "" {
+	if tid := runtime.Str("tid"); strings.TrimSpace(tid) != "" {
 		query["tid"] = tid
 	}
🤖 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_delete_slide.go` around lines 146 - 164, The
deleteSlideID and deleteSlideQuery helpers currently send trimmed opaque
identifiers. Use trimmed values only for emptiness checks, but return and place
the original raw runtime.Str values in the API query, including non-empty tid,
without silently normalizing whitespace.

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_add_slide_test.go`:
- Around line 521-560: Strengthen the error-path assertions in
TestAddSlideReportsUploadedImagesWhenPageFails and the corresponding test around
the second reported range: after errs.ProblemOf(err), assert the expected
Category and Subtype values, and validate the required Param and preserved cause
according to the typed error contract. Keep the existing uploaded-image hint
assertion, but do not rely on it as the only verification.

In `@skills/lark-slides/references/lark-slides-delete-slide.md`:
- Line 5: 更新 lark-slides 删除幻灯片文档中的参数说明,将“ID 是普通 flag”和“Risk 是
write”改为更自然明确的中文,表述为 ID 使用普通 flag 而非 --params JSON 串,并说明风险级别为 write 且不需要 --yes。

---

Duplicate comments:
In `@shortcuts/slides/slides_delete_slide.go`:
- Around line 146-164: The deleteSlideID and deleteSlideQuery helpers currently
send trimmed opaque identifiers. Use trimmed values only for emptiness checks,
but return and place the original raw runtime.Str values in the API query,
including non-empty tid, without silently normalizing whitespace.
🪄 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 Plus

Run ID: 8e393a46-0971-4bf7-aba4-d609eb064a08

📥 Commits

Reviewing files that changed from the base of the PR and between b31c209 and 735e988.

📒 Files selected for processing (23)
  • shortcuts/slides/helpers.go
  • shortcuts/slides/helpers_test.go
  • shortcuts/slides/shortcuts.go
  • shortcuts/slides/slides_add_slide.go
  • shortcuts/slides/slides_add_slide_test.go
  • shortcuts/slides/slides_create.go
  • shortcuts/slides/slides_delete_slide.go
  • shortcuts/slides/slides_delete_slide_test.go
  • shortcuts/slides/slides_errors.go
  • shortcuts/slides/slides_errors_test.go
  • shortcuts/slides/slides_media_upload.go
  • skills/lark-slides/SKILL.md
  • skills/lark-slides/references/lark-slides-add-slide.md
  • skills/lark-slides/references/lark-slides-create.md
  • skills/lark-slides/references/lark-slides-delete-slide.md
  • skills/lark-slides/references/lark-slides-media-upload.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md
  • skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md
  • skills/lark-slides/references/troubleshooting.md
  • skills/lark-slides/references/xml-schema-quick-ref.md
  • tests/cli_e2e/slides/coverage.md
  • tests/cli_e2e/slides/slides_slide_add_delete_dryrun_test.go
  • tests/cli_e2e/slides/slides_slide_add_delete_workflow_test.go
💤 Files with no reviewable changes (1)
  • skills/lark-slides/references/troubleshooting.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • skills/lark-slides/references/lark-slides-media-upload.md
  • tests/cli_e2e/slides/coverage.md
  • skills/lark-slides/references/xml-schema-quick-ref.md

Comment on lines +521 to +560
func TestAddSlideReportsUploadedImagesWhenPageFails(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "chart.png"), []byte("png-bytes"), 0o600); err != nil {
t.Fatalf("write fixture: %v", err)
}
withSlidesTestWorkingDir(t, dir)

f, stdout, _, reg := cmdutil.TestFactory(t, slidesTestConfig(t, ""))
reg.Register(&httpmock.Stub{
Method: "POST",
URL: "/open-apis/drive/v1/medias/upload_all",
Body: map[string]interface{}{"code": 0, "data": map[string]interface{}{"file_token": "tok_chart"}},
})
reg.Register(&httpmock.Stub{
Method: "POST",
URL: "/open-apis/slides_ai/v1/xml_presentations/pres_img/slide",
Body: map[string]interface{}{"code": 3350001, "msg": "invalid slide xml"},
})

slideXML := `<slide xmlns="http://www.larkoffice.com/sml/2.0"><data>` +
`<img src="@./chart.png" topLeftX="10" topLeftY="10" width="100" height="100"/>` +
`</data></slide>`

err := runSlidesShortcut(t, f, stdout, SlidesAddSlide, []string{
"+add-slide",
"--presentation", "pres_img",
"--slide", slideXML,
"--as", "user",
})
if err == nil {
t.Fatal("expected the backend rejection to surface")
}
problem, ok := errs.ProblemOf(err)
if !ok {
t.Fatalf("err = %v, want typed problem metadata", err)
}
if !strings.Contains(problem.Hint, "1 image(s) were uploaded before the page failed") {
t.Fatalf("Hint = %q, want the already-uploaded count", problem.Hint)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Assert typed Category/Subtype, not just problem.Hint.

Both tests fetch errs.ProblemOf(err) and only check ok plus a Hint substring; neither asserts Category/Subtype. A future regression that changes the error's classification (e.g., from a typed API error to an untyped wrap) would still pass these tests as long as the hint string survives.

✅ Example addition
 	problem, ok := errs.ProblemOf(err)
 	if !ok {
 		t.Fatalf("err = %v, want typed problem metadata", err)
 	}
+	if problem.Category != errs.CategoryAPI {
+		t.Fatalf("Category = %q, want %q", problem.Category, errs.CategoryAPI)
+	}
 	if !strings.Contains(problem.Hint, "1 image(s) were uploaded before the page failed") {

As per path instructions: "Error-path tests must assert typed metadata through errs.ProblemOf (category, subtype, and param) and verify cause preservation rather than relying only on message substrings."

Also applies to: 565-601

🤖 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_add_slide_test.go` around lines 521 - 560, Strengthen
the error-path assertions in TestAddSlideReportsUploadedImagesWhenPageFails and
the corresponding test around the second reported range: after
errs.ProblemOf(err), assert the expected Category and Subtype values, and
validate the required Param and preserved cause according to the typed error
contract. Keep the existing uploaded-image hint assertion, but do not rely on it
as the only verification.

Source: Path instructions


从演示文稿删除**一页**,按 `slide_id` 指定。只改一页里的局部内容用 [`+replace-slide`](lark-slides-replace-slide.md),不要删了重建。

相比原生 [`xml_presentation.slide delete`](lark-slides-xml-presentation-slide-delete.md):`--presentation` 接受 token / `/slides/` URL / `/wiki/` URL,ID 是普通 flag 而不是 `--params` JSON 串;Risk 是 `write`,不需要 `--yes`。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the risk/flag wording.

ID 是普通 flag and Risk 是 write are awkward in Chinese. Prefer wording such as: ID 使用普通 flag,而不是 --params JSON 串;风险级别为 write,不需要 --yes。

🧰 Tools
🪛 LanguageTool

[uncategorized] ~5-~5: 您不可用“是”来表达个形容词。大部分人都平常用“很”来代替“是”。您是不是想表达"很普通"?
Context: ...oken / /slides/ URL / /wiki/ URL,ID 是普通 flag 而不是 --params JSON 串;Risk 是 `writ...

(SHI_ADHECTIVE_ERROR)

🤖 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 `@skills/lark-slides/references/lark-slides-delete-slide.md` at line 5, 更新
lark-slides 删除幻灯片文档中的参数说明,将“ID 是普通 flag”和“Risk 是 write”改为更自然明确的中文,表述为 ID 使用普通
flag 而非 --params JSON 串,并说明风险级别为 write 且不需要 --yes。

Source: Linters/SAST tools

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.

1 participant