Skip to content

feat(drive): add comment batch-query/resolve, reply CRUD and reaction shortcuts#1898

Open
zzzchao123 wants to merge 5 commits into
mainfrom
feat/drive-comment-shortcuts
Open

feat(drive): add comment batch-query/resolve, reply CRUD and reaction shortcuts#1898
zzzchao123 wants to merge 5 commits into
mainfrom
feat/drive-comment-shortcuts

Conversation

@zzzchao123

@zzzchao123 zzzchao123 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add seven comment-operation shortcuts to the drive domain, covering the remaining comment APIs — +batch-query-comments, +resolve-comment, the full reply family +add-reply / +list-replies / +update-reply / +delete-reply (batch_query / patch / reply create / list / update / delete), and +react-reply for reply emoji reactions (update_reaction) — with the same URL-parsing + wiki-unwrapping UX as +list-comments.

Changes

Command API Risk
+batch-query-comments POST /drive/v1/files/:token/comments/batch_query--comment-ids (CSV/repeated, max 100), --need-reaction read
+resolve-comment PATCH /drive/v1/files/:token/comments/:comment_id--action resolve|restoreis_solved write
+add-reply POST /drive/v1/files/:token/comments/:comment_id/replies--content reuses the +add-comment reply_elements JSON (same escaping and 10k-rune preflight), mapped to text_run/person/docs_link write
+list-replies GET .../comments/:comment_id/replies--page-size/--page-token pagination, --need-reaction, --user-id-type open_id|union_id|user_id read
+update-reply PUT .../comments/:comment_id/replies/:reply_id — whole-content replacement, same --content JSON as +add-reply write
+delete-reply DELETE .../comments/:comment_id/replies/:reply_id — requires --yes high-risk-write
+react-reply POST /drive/v2/files/:token/comments/reaction--reply-id + --emoji + --action add|delete → body reply_id/reaction_type/action write
  • All seven accept --url or --token + --type and unwrap wiki nodes automatically; shared input resolution lives in drive_comment_common.go, parameterized by each endpoint's supported file_type set. All seven accept Base (/base/ URLs, bitable/base types) and Miaoda apps targets (/page/<token> URLs, file_type=apps), matching the platform API metadata.
  • Scopes follow the per-endpoint metadata: +add-reply declares docs:document.comment:create — the replies create endpoint does not accept docs:document.comment:write_only, so declaring both would false-reject valid create-only tokens; resolve/update/delete/react keep write_only, batch-query/list keep comment:read.
  • +add-reply deliberately does not use the documented "POST .../comments with comment_id in the body" form: verified live, that variant silently creates a new standalone comment instead of replying. The dedicated replies endpoint is used instead (noted in code and in the skill guide).
  • Reply semantics, live-verified and documented in Tips + the skill guide:
    • the root reply (the comment body itself) is items[0] of the first page only — after --page-token paging, items[0] is a regular reply, so position must not be used to identify the root when paging;
    • updating a comment's root reply rewrites the comment body; deleting it deletes the whole card;
    • only the identity that created a reply can update it — cross-identity updates return 1069303 forbidden (verified in both user→bot and bot→user directions);
    • --user-id-type user_id additionally requires the contact:user.employee_id:readonly scope (99991679 without it); open_id (default) and union_id need no extra scope. --user-id-type exists so callers can match items[].user_id against the ID form they hold when checking ownership before update/delete.
  • Reaction semantics, live-verified and documented in Tips + the reactions guide:
    • the server does not validate reaction_type — arbitrary strings are accepted and persisted as broken reactions, so --emoji is validated locally against the 149-value platform enum from the API metadata (case-sensitive: THUMBSUP vs ThumbsDown);
    • deleted reactions linger as count=0 entries in need_reaction reads, so presence checks filter by count>0;
    • add/delete are idempotent, and delete cancels only the caller's own reaction.
  • Output hardening: +list-comments / +batch-query-comments / +list-replies now always emit items as a JSON array (shared driveCommentItems helper) — previously a server response omitting items would surface "items": null and break jq consumers iterating .data.items[].
  • The seven new commands declare wiki:node:read as the wiki-unwrap conditional scope: live verification with both identities showed get_node accepts wiki:wiki / wiki:wiki:readonly / wiki:node:read (a token carrying only wiki:node:retrieve is rejected with 99991679), and the sheets/slides domains already declare wiki:node:read for the same unwrap step. Existing drive/base commands that still declare wiki:node:retrieve are intentionally left unchanged in this PR; aligning them is a candidate follow-up.
  • Skill docs (skills/lark-drive/SKILL.md, references/lark-drive-comments-guide.md, references/lark-drive-reactions.md) updated with routing rules and the live-verified caveats above (plus: whole/solved comments reject replies; rapid resolve/restore flips can hit HTTP 429).

Test Plan

  • Unit tests pass — make unit-test (-race) green; new-file statement coverage 94%+ (remaining lines are the CLI-unreachable defensive branches in DryRun/Execute closures); contract tests assert payload values directly (returned reply IDs and nested content on +list-replies, converted text_run.text / person.user_id in +add-reply / +update-reply request bodies)
  • Manual local verification confirms the lark-cli drive +<command> flows work as expected — full live round trips on a real wiki→docx document with both --as user and --as bot: list → batch-query → add-reply → list-replies (incl. --page-size 1 two-page paging and --user-id-type forms) → update-reply → react add/delete → resolve/restore → delete-reply, document restored to its original state afterwards; cross-identity update rejection probed in both directions, and the unvalidated-reaction_type / count=0 tombstone behaviors probed live
  • Dry-run e2e contract tests (tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go) pin method/URL/params/body shapes for all seven commands incl. base/apps targets and the wiki 2-step plans; tests/cli_e2e/drive/coverage.md updated (39 leaf commands, 20 covered, 51.3%, incl. the +delete coverage that landed on main)
  • Self-contained live E2E workflow (tests/cli_e2e/drive/drive_comment_ops_workflow_test.go, opt-in via LARK_DRIVE_MD_COMMENT_E2E=1, same gate as the existing file-comment workflow): creates a Markdown file + file comment fixture, batch-queries it by ID, attaches a reply, lists it back, rewrites it via +update-reply (polling +list-replies until the new text lands), attaches and removes a THUMBSUP reaction (polling +list-replies --need-reaction with count>0 presence checks), resolves/restores with polling reads between state flips, deletes the reply, and cleans up — passed live in 19.8s
  • go vet ./..., gofmt -l . clean, go mod tidy no-op, golangci-lint run --new-from-rev=origin/main 0 issues

Related Issues

  • None

Summary by CodeRabbit

  • New Features
    • Added Drive comment/reply shortcuts: +batch-query-comments, +resolve-comment, +add-reply, +list-replies, +update-reply, +delete-reply, and +react-reply.
    • Supports document, Wiki (auto-unwrapped), apps page, and Base targets, with pagination, optional reactions, and user-id-type where applicable.
    • --dry-run now shows the exact API call plan for both direct and Wiki flows.
  • Bug Fixes
    • Normalizes omitted items to an empty array and count=0 for comment/reply lists.
  • Documentation
    • Updated Drive comment/reply guides to recommend the shortcut workflow and clarify reply text escaping.
  • Tests
    • Added unit and CLI E2E coverage for validation, error handling, and dry-run/request/output contracts.

@zzzchao123
zzzchao123 requested a review from liangshuo-1 as a code owner July 15, 2026 07:04
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


zchao.007 seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions Bot added domain/base PR touches the base domain domain/ccm PR touches the ccm domain size/L Large or sensitive change across domains or core paths labels Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 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 seven Drive comment and reply shortcuts for querying, resolving, creating, listing, updating, deleting, and reacting. Shared handling supports URL/token/type resolution, Wiki unwrapping, validation, dry-run planning, tests, registry integration, and documentation.

Changes

Drive comment workflows

Layer / File(s) Summary
Comment target resolution and validation
shortcuts/drive/drive_comment_common.go, shortcuts/drive/drive_comment_common_test.go
Shared parsing validates URL/token/type inputs, normalizes resource types, resolves Wiki nodes, validates path identifiers, normalizes missing items, and builds common output fields.
Batch comment querying
shortcuts/drive/drive_batch_query_comments.go, shortcuts/drive/drive_batch_query_comments_test.go, shortcuts/drive/drive_list_comments.go
+batch-query-comments validates and normalizes comment IDs, supports reaction data, handles Apps/Base targets, queries resolved targets, and plans Wiki two-step execution. Existing comment listing normalizes omitted items.
Reply creation
shortcuts/drive/drive_add_reply.go, shortcuts/drive/drive_add_reply_test.go
+add-reply parses structured content, converts elements to Drive v1 payloads, creates replies, extracts reply IDs, and supports Wiki resolution.
Reply listing and updating
shortcuts/drive/drive_list_replies.go, shortcuts/drive/drive_update_reply.go, shortcuts/drive/*_test.go
+list-replies adds pagination, reaction, and user ID parameters; +update-reply replaces reply content. Both support validation, direct execution, Wiki resolution, and dry-run plans.
Comment state and reply deletion
shortcuts/drive/drive_resolve_comment.go, shortcuts/drive/drive_delete_reply.go, shortcuts/drive/*_test.go
Resolve/restore updates is_solved; reply deletion issues DELETE requests. Both validate identifiers and support direct and Wiki-backed targets.
Reply reactions
shortcuts/drive/drive_react_reply.go, shortcuts/drive/drive_react_reply_test.go
+react-reply validates reaction types and add/delete actions, posts reply reactions, and supports direct and Wiki-backed dry-run flows.
Shortcut integration and workflow guidance
shortcuts/drive/shortcuts.go, shortcuts/drive/shortcuts_test.go, skills/lark-drive/*, tests/cli_e2e/drive/*
Registers seven commands, documents usage and escaping rules, updates coverage metrics, and adds dry-run plus opt-in live workflow coverage.

Estimated code review effort: 5 (Critical) | ~90 minutes

Possibly related PRs

  • larksuite/cli#1845: Provides the shared Drive comment-family helpers and omitted-item normalization used by these shortcuts.

Suggested labels: size/XL, domain/ccm, feature

Suggested reviewers: liangshuo-1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.00% 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
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.
Title check ✅ Passed The title clearly summarizes the main change: new drive comment/reply and reaction shortcuts.
Description check ✅ Passed The description matches the required template with Summary, Changes, Test Plan, and Related Issues sections filled in.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/drive-comment-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.

@zzzchao123
zzzchao123 requested a review from wittam-01 July 15, 2026 07:05
@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from 81c45ba to e1e08b2 Compare July 15, 2026 07:12

@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

🤖 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 `@tests/cli_e2e/drive/coverage.md`:
- Around line 32-35: Add a self-contained live E2E workflow test file covering
the shortcut flows in TestDrive_CommentOpsDryRun: +batch-query-comments,
+resolve-comment, +add-reply, and +delete-reply. Use the live API to create
required comments and replies, exercise each operation including both resolve
and restore behavior, verify responses and state changes, then clean up all
created resources even when assertions fail.

In `@tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go`:
- Around line 18-181: Add a self-contained live E2E test alongside
TestDrive_CommentOpsDryRun covering +batch-query-comments, +resolve-comment,
+add-reply, and +delete-reply. Create the required document/comment fixture,
exercise each shortcut against the live service with assertions on the
round-trip results, and ensure cleanup runs reliably via test cleanup even when
assertions fail.
🪄 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: c98e4543-2937-4a11-9d83-f1381cd3423b

📥 Commits

Reviewing files that changed from the base of the PR and between 49b4ccc and 81c45ba.

📒 Files selected for processing (23)
  • internal/qualitygate/diff/diff.go
  • internal/qualitygate/diff/diff_test.go
  • shortcuts/base/base_resolve.go
  • shortcuts/drive/drive_add_reply.go
  • shortcuts/drive/drive_add_reply_test.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_batch_query_comments_test.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_comment_common_test.go
  • shortcuts/drive/drive_delete_reply.go
  • shortcuts/drive/drive_delete_reply_test.go
  • shortcuts/drive/drive_export.go
  • shortcuts/drive/drive_import.go
  • shortcuts/drive/drive_inspect.go
  • shortcuts/drive/drive_list_comments.go
  • shortcuts/drive/drive_resolve_comment.go
  • shortcuts/drive/drive_resolve_comment_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-comments-guide.md
  • tests/cli_e2e/drive/coverage.md
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go

Comment thread tests/cli_e2e/drive/coverage.md Outdated
Comment thread tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
Comment thread internal/qualitygate/diff/diff.go Outdated
Comment thread shortcuts/base/base_resolve.go
Comment thread shortcuts/drive/shortcuts_test.go
@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from e1e08b2 to 3ea7e26 Compare July 15, 2026 07:39
@github-actions github-actions Bot removed the domain/base PR touches the base domain label Jul 15, 2026
@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from 3ea7e26 to 11e1595 Compare July 15, 2026 07:47
Comment thread shortcuts/drive/drive_batch_query_comments.go Outdated
Comment thread shortcuts/drive/drive_add_reply.go Outdated
@wittam-01

Copy link
Copy Markdown
Collaborator

Current PR head is still mergeable=CONFLICTING against latest main. Please rebase/merge main and resolve the doc/coverage conflicts while preserving the existing +list-comments apps support from main.

For the apps regression check, I used the provided page URL:

./lark-cli drive +list-comments --url "https://bytedance.feishu.cn/page/N1BWmMrqndT5ZcamAIBcnvDLnOf/" --solved-status all --page-size 100 --as bot --format json

This succeeds as bot and returns file_type=apps, count=15, has_more=false, so it is a good fixture to keep the apps path covered after the rebase.

@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from 11e1595 to 41a7462 Compare July 15, 2026 08:02

@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

🤖 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-drive/SKILL.md`:
- Around line 104-105: 更新 SKILL.md 中关于评论文本转义的说明,明确使用 drive +add-comment 或 drive
+add-reply shortcut 时传入原始文本,由 shortcut 自动转义;直接调用 drive file.comments create_v2 或
drive file.comment.replys update 时,调用方必须先将文本中的 < 和 > 转义后再提交,避免 shortcut 调用方重复转义。
🪄 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: 7ec789d4-d494-456d-87e5-e38253e05dac

📥 Commits

Reviewing files that changed from the base of the PR and between 3ea7e26 and 41a7462.

📒 Files selected for processing (16)
  • shortcuts/drive/drive_add_reply.go
  • shortcuts/drive/drive_add_reply_test.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_batch_query_comments_test.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_comment_common_test.go
  • shortcuts/drive/drive_delete_reply.go
  • shortcuts/drive/drive_delete_reply_test.go
  • shortcuts/drive/drive_resolve_comment.go
  • shortcuts/drive/drive_resolve_comment_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-comments-guide.md
  • tests/cli_e2e/drive/coverage.md
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • shortcuts/drive/drive_delete_reply_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_delete_reply.go
  • shortcuts/drive/drive_batch_query_comments_test.go
  • shortcuts/drive/drive_resolve_comment_test.go
  • shortcuts/drive/shortcuts_test.go
  • shortcuts/drive/drive_comment_common.go
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
  • shortcuts/drive/drive_resolve_comment.go
  • tests/cli_e2e/drive/coverage.md
  • shortcuts/drive/drive_comment_common_test.go
  • shortcuts/drive/drive_add_reply.go
  • shortcuts/drive/drive_add_reply_test.go
  • skills/lark-drive/references/lark-drive-comments-guide.md

Comment thread skills/lark-drive/SKILL.md Outdated
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.66982% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.12%. Comparing base (7081960) to head (d663c4a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/drive/drive_react_reply.go 93.40% 3 Missing and 3 partials ⚠️
shortcuts/drive/drive_resolve_comment.go 92.77% 3 Missing and 3 partials ⚠️
shortcuts/drive/drive_add_reply.go 96.42% 2 Missing and 2 partials ⚠️
shortcuts/drive/drive_batch_query_comments.go 94.93% 2 Missing and 2 partials ⚠️
shortcuts/drive/drive_delete_reply.go 94.28% 2 Missing and 2 partials ⚠️
shortcuts/drive/drive_list_replies.go 95.29% 2 Missing and 2 partials ⚠️
shortcuts/drive/drive_update_reply.go 95.06% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1898      +/-   ##
==========================================
+ Coverage   74.96%   75.12%   +0.16%     
==========================================
  Files         892      900       +8     
  Lines       94058    94796     +738     
==========================================
+ Hits        70506    71215     +709     
- Misses      18139    18152      +13     
- Partials     5413     5429      +16     

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

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#feat/drive-comment-shortcuts -y -g

@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from 41a7462 to b7aea0b Compare July 15, 2026 09:37
@zzzchao123
zzzchao123 requested a review from wittam-01 July 15, 2026 09:44
@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from b7aea0b to a5e2d29 Compare July 15, 2026 10:14

@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

🧹 Nitpick comments (1)
shortcuts/drive/drive_batch_query_comments_test.go (1)

1-1: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

API-error propagation tests only assert on message substrings, not on typed error classification.

All four "PropagatesAPIError" tests share the same gap: they check strings.Contains(err.Error(), "...") but never verify the error remains a typed API error (e.g., via errs.ProblemOf(err)Category == errs.CategoryAPI). A regression where runtime.CallAPITyped's typed error gets rewrapped as a plain error would pass all four tests silently.

  • shortcuts/drive/drive_batch_query_comments_test.go#L353-373: after the substring check, add if p, ok := errs.ProblemOf(err); !ok || p.Category != errs.CategoryAPI { t.Fatalf(...) }.
  • shortcuts/drive/drive_add_reply_test.go#L261-282: add the same errs.ProblemOf Category assertion after the substring check.
  • shortcuts/drive/drive_resolve_comment_test.go#L266-287: add the same errs.ProblemOf Category assertion after the substring check.
  • shortcuts/drive/drive_delete_reply_test.go#L176-198: add the same errs.ProblemOf Category assertion after the substring check.

Based on learnings, in larksuite/cli Go test suites for shortcuts domain packages, when exercising error paths, tests should "assert Category == errs.CategoryAPI and verify Subtype is non-empty/populated" rather than relying only on message text. This is also consistent with the path instruction that "**/*_test.go... contract tests must assert the new field or behavior directly rather than relying only on happy-path substrings."

🤖 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/drive/drive_batch_query_comments_test.go` at line 1, Update all
four PropagatesAPIError tests in the drive shortcuts test suite to classify the
returned error with errs.ProblemOf(err) after the existing message assertion.
Fail unless extraction succeeds, Category equals errs.CategoryAPI, and Subtype
is non-empty, preserving the current message checks while directly validating
typed API-error propagation.

Sources: Path instructions, Learnings

🤖 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/drive/drive_add_reply_test.go`:
- Around line 308-320: Update TestDriveAddReplyInvalidContent to call
assertDriveCommentValidationError(t, err, "--content") in addition to verifying
the invalid-JSON message, ensuring the returned error is typed and attributed to
the --content flag.

---

Nitpick comments:
In `@shortcuts/drive/drive_batch_query_comments_test.go`:
- Line 1: Update all four PropagatesAPIError tests in the drive shortcuts test
suite to classify the returned error with errs.ProblemOf(err) after the existing
message assertion. Fail unless extraction succeeds, Category equals
errs.CategoryAPI, and Subtype is non-empty, preserving the current message
checks while directly validating typed API-error propagation.
🪄 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: e8d2da51-2003-4953-8cf2-384b1db7f06a

📥 Commits

Reviewing files that changed from the base of the PR and between b7aea0b and a5e2d29.

📒 Files selected for processing (17)
  • shortcuts/drive/drive_add_reply.go
  • shortcuts/drive/drive_add_reply_test.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_batch_query_comments_test.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_comment_common_test.go
  • shortcuts/drive/drive_delete_reply.go
  • shortcuts/drive/drive_delete_reply_test.go
  • shortcuts/drive/drive_resolve_comment.go
  • shortcuts/drive/drive_resolve_comment_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-comments-guide.md
  • tests/cli_e2e/drive/coverage.md
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
  • tests/cli_e2e/drive/drive_comment_ops_workflow_test.go
🚧 Files skipped from review as they are similar to previous changes (12)
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/drive_delete_reply.go
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_comment_common_test.go
  • shortcuts/drive/drive_resolve_comment.go
  • tests/cli_e2e/drive/drive_comment_ops_workflow_test.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_add_reply.go
  • shortcuts/drive/shortcuts_test.go
  • tests/cli_e2e/drive/coverage.md
  • skills/lark-drive/references/lark-drive-comments-guide.md

Comment thread shortcuts/drive/drive_add_reply_test.go
@github-actions github-actions Bot added size/XL Architecture-level or global-impact change and removed size/L Large or sensitive change across domains or core paths labels Jul 17, 2026
@zzzchao123 zzzchao123 changed the title feat(drive): add comment batch-query/resolve/reply shortcuts feat(drive): add comment batch-query/resolve and reply CRUD shortcuts Jul 17, 2026
@zzzchao123 zzzchao123 self-assigned this Jul 17, 2026

@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

🤖 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/drive/drive_list_replies_test.go`:
- Around line 265-284: Strengthen TestDriveListRepliesPropagatesAPIError in
shortcuts/drive/drive_list_replies_test.go:265-284 by asserting the returned
error is typed with Category equal to errs.CategoryAPI and a non-empty subtype,
while retaining the message assertion. Add the same typed-error assertions to
the corresponding error test in
shortcuts/drive/drive_update_reply_test.go:212-233, verifying API errors remain
unchanged without requiring a dedicated subtype constant.
- Around line 59-69: The tests only validate response shape, not that reply data
is preserved. In shortcuts/drive/drive_list_replies_test.go at lines 59-69,
assert each returned item’s reply_id values; in
shortcuts/drive/drive_update_reply_test.go at lines 46-62, assert the converted
text and mentioned-user identifier. Update both contract tests to verify these
exact echoed payload values.
🪄 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: 3ab8d1b2-85d2-4bf6-889e-149f3d71635b

📥 Commits

Reviewing files that changed from the base of the PR and between a5e2d29 and a2aa045.

📒 Files selected for processing (17)
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_batch_query_comments_test.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_list_comments.go
  • shortcuts/drive/drive_list_comments_test.go
  • shortcuts/drive/drive_list_replies.go
  • shortcuts/drive/drive_list_replies_test.go
  • shortcuts/drive/drive_resolve_comment.go
  • shortcuts/drive/drive_update_reply.go
  • shortcuts/drive/drive_update_reply_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-comments-guide.md
  • tests/cli_e2e/drive/coverage.md
  • tests/cli_e2e/drive/drive_comment_ops_dryrun_test.go
  • tests/cli_e2e/drive/drive_comment_ops_workflow_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • shortcuts/drive/shortcuts_test.go
  • shortcuts/drive/drive_batch_query_comments.go
  • shortcuts/drive/drive_resolve_comment.go
  • shortcuts/drive/drive_comment_common.go
  • shortcuts/drive/drive_batch_query_comments_test.go

Comment thread shortcuts/drive/drive_list_replies_test.go
Comment on lines +265 to +284
func TestDriveListRepliesPropagatesAPIError(t *testing.T) {
f, stdout, _, reg := cmdutil.TestFactory(t, driveTestConfig())
reg.Register(&httpmock.Stub{
Method: "GET",
URL: "/open-apis/drive/v1/files/docxResource/comments/comment_1/replies",
Body: map[string]interface{}{
"code": 1069301,
"msg": "comment not found",
},
})

err := mountAndRunDrive(t, DriveListReplies, []string{
"+list-replies",
"--url", "https://example.larksuite.com/docx/docxResource",
"--comment-id", "comment_1",
"--as", "user",
}, f, stdout)
if err == nil || !strings.Contains(err.Error(), "comment not found") {
t.Fatalf("expected API error to propagate, 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 that API errors remain typed.

Message-only assertions permit replacing CallAPITyped passthrough with an untyped error without failing tests.

  • shortcuts/drive/drive_list_replies_test.go#L265-L284: assert Category == errs.CategoryAPI and a non-empty subtype.
  • shortcuts/drive/drive_update_reply_test.go#L212-L233: add the same typed-error assertions.

As per coding guidelines, shortcut API errors must be returned unchanged and contract tests must assert that behavior directly. Based on learnings, assert CategoryAPI and a populated subtype rather than a dedicated API subtype constant.

📍 Affects 2 files
  • shortcuts/drive/drive_list_replies_test.go#L265-L284 (this comment)
  • shortcuts/drive/drive_update_reply_test.go#L212-L233
🤖 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/drive/drive_list_replies_test.go` around lines 265 - 284,
Strengthen TestDriveListRepliesPropagatesAPIError in
shortcuts/drive/drive_list_replies_test.go:265-284 by asserting the returned
error is typed with Category equal to errs.CategoryAPI and a non-empty subtype,
while retaining the message assertion. Add the same typed-error assertions to
the corresponding error test in
shortcuts/drive/drive_update_reply_test.go:212-233, verifying API errors remain
unchanged without requiring a dedicated subtype constant.

Sources: Coding guidelines, Learnings

@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from a2aa045 to c0b66f2 Compare July 17, 2026 03:14
zchao.007 added 4 commits July 17, 2026 11:26
Add four comment-operation shortcuts to the drive domain, all accepting
--url / --token + --type with automatic wiki-node unwrapping:

- +batch-query-comments: POST files/:token/comments/batch_query
  (--comment-ids CSV/repeated, max 100; --need-reaction)
- +resolve-comment: PATCH files/:token/comments/:comment_id
  (--action resolve|restore -> is_solved true/false)
- +add-reply: POST files/:token/comments/:comment_id/replies
  (--content reuses the +add-comment reply_elements JSON, its escaping
  and length preflight, mapped to text_run/person/docs_link)
- +delete-reply: DELETE .../comments/:comment_id/replies/:reply_id
  (high-risk-write, requires --yes)

Shared --url/--token/--type resolution and wiki unwrapping live in
drive_comment_common.go, parameterized by each endpoint's supported
file_type set. Supported targets follow the platform API metadata:
doc/docx/sheet/file/slides plus bitable (base alias) on all four, and
Miaoda apps (/page/<token> URLs or bare tokens with --type apps),
matching the apps comment support +list-comments gained on main.

Scopes follow the per-endpoint metadata: +add-reply requires
docs:document.comment:create (the replies create endpoint does not
accept docs:document.comment:write_only), while resolve/delete keep
write_only and batch-query keeps docs:document.comment:read.

Note on +add-reply: the documented alternative (POST .../comments with
comment_id in the request body) does not reply in practice - verified
live, it silently creates a new standalone comment - so the shortcut
uses the dedicated replies endpoint instead.

Verified live against a wiki->docx document with both user and bot
identities: list -> batch-query -> add-reply -> resolve/restore ->
delete-reply round trip. Coverage: dry-run e2e contract tests plus a
self-contained opt-in live workflow (TestDriveCommentOpsWorkflow,
gated by LARK_DRIVE_MD_COMMENT_E2E) that creates a Markdown-file
comment fixture, exercises all four shortcuts, and cleans up.
Complete the file.comment.replys family with the two remaining
operations, following the shared comment-op machinery
(--url/--token/--type input, Wiki unwrapping, base alias, apps support):

- drive +list-replies: page through one comment's replies
  (GET .../comments/:comment_id/replies) with --page-size/--page-token/
  --need-reaction/--user-id-type. The root reply (the comment body) is
  items[0] of the first page only; docs and tips spell out that paged
  items[0] is a regular reply, and --user-id-type lets callers align
  items[].user_id with the ID form they hold for ownership checks.
- drive +update-reply: replace a reply's content
  (PUT .../comments/:comment_id/replies/:reply_id) with the same
  reply_elements JSON as +add-reply (text auto-escaped). Declares
  docs:document.comment:write_only (in the endpoint's any-of scope set,
  consistent with +resolve-comment/+delete-reply).

Live-verified behaviors (encoded in Tips and the comments guide):
- updating a comment's root reply rewrites the comment body itself;
- only the creator identity may update a reply — other identities get
  API error 1069303 (forbidden), verified in both directions;
- user_id_type is honored by the endpoint (open_id default, union_id
  probed live); the user_id form additionally requires the
  contact:user.employee_id:readonly scope (99991679 without it).

Tests and docs shipped in the same change:
- unit tests cover execute (direct + wiki), pagination/reaction/
  user-id-type params, request-body element mapping, validation
  branches (incl. enum rejection), API error propagation, and both
  dry-run branches;
- e2e: three new TestDrive_CommentOpsDryRun cases (docx list with query
  wiring, wiki resolve plan, base update) and TestDriveCommentOpsWorkflow
  now lists the created reply and rewrites it, polling +list-replies
  until the new text lands before the resolve/restore flips;
- skills/lark-drive SKILL.md + comments guide route the two new
  commands and document pagination, first-page root-reply semantics,
  ownership, and user-id-type alignment; coverage.md metrics move to
  17/38 covered.
Drop clauses that restate adjacent code or duplicate sibling doc
comments (flagEnum's append-order narration and +list-comments
provenance; parseDriveResolveCommentAction's inaccurate single-home
claim). The load-bearing constraints — wiki resolved to a wire type
before the API call, base normalized to bitable, the CLI-unreachable
error branch guarding direct callers — stay.
+list-comments, +batch-query-comments, and +list-replies passed the
server's items field straight through common.GetSlice, so a success
response omitting items (or carrying null) surfaced as "items": null —
jq consumers iterating .data.items[] fail on that with "Cannot iterate
over null" (exit 5).

Normalize through a shared driveCommentItems helper that falls back to
an empty slice, and pin the omitted-items response shape in unit tests
for all three commands.

Live probes could not force the null shape today (an empty
+list-comments page returned items: [], and beyond-end +list-replies
pagination returns API error 1069307), so this hardens the output
contract against server-shape drift rather than fixing a reproduced
live failure.
@zzzchao123
zzzchao123 force-pushed the feat/drive-comment-shortcuts branch from c0b66f2 to 09112f6 Compare July 17, 2026 03:58
Wrap file.comment.reply.reactions update_reaction (POST
/drive/v2/files/:file_token/comments/reaction) with the shared
comment-family machinery: --url/--token/--type input with Wiki
unwrapping, base alias and apps support, and --reply-id/--emoji/
--action add|delete mapped to the request body. Declares
docs:document.comment:write_only (in the endpoint's any-of scope set,
consistent with the other comment write shortcuts).

Live-verified behaviors (encoded in Tips, the reactions guide, and the
workflow test):
- the server does NOT validate reaction_type — arbitrary strings are
  accepted and persisted as broken reactions on the reply, so --emoji
  is validated locally against the 149-value platform enum from the
  API metadata (case-sensitive: THUMBSUP vs ThumbsDown);
- deleted reactions linger as count=0 entries in need_reaction reads,
  so presence checks must filter by count>0;
- add/delete are idempotent; delete cancels only the caller's own
  reaction.

Tests and docs shipped in the same change:
- unit tests cover execute (direct + wiki), request-body value mapping,
  emoji/action validation (incl. case sensitivity), typed API error
  passthrough via the new assertDriveCommentAPIError helper, and both
  dry-run branches;
- e2e: two TestDrive_CommentOpsDryRun cases (docx add with body values,
  wiki resolve plan for delete) and TestDriveCommentOpsWorkflow now
  attaches and removes a THUMBSUP reaction with count>0 polling;
- skills/lark-drive SKILL.md + reactions guide route reaction writes
  through the shortcut and document the tombstone / no-server-validation
  / idempotency findings; coverage.md metrics move to 20/39 covered.
@zzzchao123 zzzchao123 changed the title feat(drive): add comment batch-query/resolve and reply CRUD shortcuts feat(drive): add comment batch-query/resolve, reply CRUD and reaction shortcuts Jul 17, 2026
| [`+add-comment`](references/lark-drive-add-comment.md) | 给 doc/docx/file/sheet/slides/base(bitable) 添加评论,也支持解析到这些类型的 wiki URL;评论统计、回复和 reaction 细则见 [`lark-drive-comments-guide.md`](references/lark-drive-comments-guide.md)。 |
| [`+list-comments`](references/lark-drive-list-comments.md) | 获取 doc/docx/sheet/file/slides/base(bitable)/apps 评论列表;优先传 URL,支持 wiki 自动解包和妙搭 `/page/<token>` URL。 |
| `+batch-query-comments` | 按评论 ID 批量获取 doc/docx/sheet/file/slides/base(bitable)/apps 评论(`--comment-ids` 逗号分隔或重复传,单次最多 100 个,`--need-reaction` 附带 reaction);支持 URL(含妙搭 `/page/<token>`)与 wiki 自动解包。 |
| `+resolve-comment` | 解决或恢复 doc/docx/sheet/file/slides/base(bitable)/apps 上的评论:`--comment-id` + `--action resolve\|restore`;支持 URL(含妙搭 `/page/<token>`)与 wiki 自动解包。 |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+resolve-comment,名称看起来是解决评论的含义,通过action又能控制恢复,有歧义,换个标题看下

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

PR Quality Summary

CI did not complete successfully. Use the failed check links below to decide whether this PR needs a code change or a rerun.

Failed checks

Scopes: []string{"docs:document.comment:read"},
ConditionalScopes: []string{"wiki:node:read"},
AuthTypes: []string{"user", "bot"},
Flags: append(driveCommentTargetFlags(driveBatchQueryCommentsOp),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

还支持need-relation

common.Flag{Name: "page-size", Type: "int", Default: "50", Desc: "page size, 1-100"},
common.Flag{Name: "page-token", Desc: "pagination token from previous response"},
common.Flag{Name: "need-reaction", Type: "bool", Desc: "include reaction data on replies"},
common.Flag{Name: "user-id-type", Desc: "user ID type for items[].user_id: open_id (default), union_id, user_id", Enum: []string{"open_id", "union_id", "user_id"}},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

不要支持user-id-type类型,默认使用open_id就好,bot请求场景,如果传user_id好像会报错。


## 获取回复

- 获取某条评论下的回复优先使用 `drive +list-replies --url '<DOC_URL>' --comment-id <id>`,不要优先手写 `drive file.comment.replys list`;支持 `doc`/`docx`/`sheet`/`file`/`slides`/`bitable`/`apps` 及解析到它们的 wiki URL/token。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

支持传type和token不


## 获取回复

- 获取某条评论下的回复优先使用 `drive +list-replies --url '<DOC_URL>' --comment-id <id>`,不要优先手写 `drive file.comment.replys list`;支持 `doc`/`docx`/`sheet`/`file`/`slides`/`bitable`/`apps` 及解析到它们的 wiki URL/token。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

「及解析到它们的 wiki URL/token。」读起来有点奇怪,预期是支持传url(包括wiki url);或者type+token。如果是wiki场景,内部会解析道真实资源的type和token

- `is_solved=true` 的已解决评论不支持回复;遇到时提示“该评论已被解决,无法回复”。
- 当目标评论不能回复时,只提示限制,不要自动替用户寻找其他可回复评论。

## 获取回复

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这些看是不是这期就抽成单独的ref skill,只在这里面引导就好,长期也是要抽出去的

- 遍历评论卡片并顺带拿 reaction:使用 `drive +list-comments --need-reaction`。
- 已知评论 ID,批量查看 reaction:使用 `drive +batch-query-comments --need-reaction`。
- 某张评论卡片下继续翻页拉 reply reaction:使用 `drive +list-replies --need-reaction`,每一页都要持续带
- 返回形状:`items[].reactions[]` 为 `{reaction_key, count, ahead_users[]}`;**`count=0` 的条目是已删除 reaction 的残留(已实测确认),统计与判断是否存在都要按 `count>0` 过滤**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

不要带这种「已实测确认」的描述

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/ccm PR touches the ccm domain size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants