Skip to content

feat(drive): add +sync for two-way local/Drive sync#873

Open
fangshuyu-768 wants to merge 1 commit into
mainfrom
feat/drive-sync
Open

feat(drive): add +sync for two-way local/Drive sync#873
fangshuyu-768 wants to merge 1 commit into
mainfrom
feat/drive-sync

Conversation

@fangshuyu-768
Copy link
Copy Markdown
Collaborator

@fangshuyu-768 fangshuyu-768 commented May 14, 2026

Summary

This PR adds drive +sync for two-way sync between a local directory and a Drive folder.

What’s included

  • Add drive +sync to compute a diff and apply sync actions in one command
  • Reuse the existing +status, +pull, and +push flow for file discovery and transfer
  • Support these conflict resolution modes for files modified on both sides:
    • remote-wins (default)
    • local-wins
    • keep-both
    • ask
  • Add --quick support so +status / +sync can use modified time comparison instead of SHA-256
  • Add --if-exists=smart to drive +pull and drive +push so repeated syncs can skip files that are already up to date based on modified time
  • Keep +sync non-destructive: it only adds or updates files and does not delete files on either side

Output

+sync returns:

  • the detection mode (exact or quick)
  • the diff groups (new_local, new_remote, modified, unchanged)
  • an execution summary
  • per-file action results

Test Plan

  • Unit tests for sync conflict handling and quick mode
  • Unit tests for --if-exists=smart in +pull and +push
  • Dry-run E2E coverage for +pull, +push, and +status
  • Live E2E coverage for +status --quick
  • go build ./...

Summary by CodeRabbit

New Features

  • Added drive +sync command for bidirectional synchronization between a local directory and Drive folder, with configurable conflict resolution options
  • Added --quick flag to drive +status for rapid detection using modification times instead of SHA-256 hashing
  • Added --if-exists=smart support to drive +push and enhanced drive +pull with smart policy for timestamp-based efficient skipping

Documentation

  • Updated Drive shortcuts documentation with new features and behavior details

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request adds time-based incremental sync features across Drive shortcuts. The changes introduce smart --if-exists=smart mode for +pull/+push (skipping when remote timestamps indicate no change), a --quick mode for +status (comparing modified_time without downloading file contents), and a new two-way +sync shortcut supporting conflict resolution strategies. All changes include comprehensive testing and documentation updates.

Changes

Drive Smart Time-Based Sync and Bidirectional Sync

Layer / File(s) Summary
Pull smart mode test coverage
shortcuts/drive/drive_pull_test.go
Six test cases validate +pull --if-exists smart skip/download logic: skips when local is up-to-date, downloads when remote is newer, and safely falls back on missing/invalid metadata or unresolvable paths. Smart mode also correctly ignores remote size mismatches.
Push smart incremental mode
shortcuts/drive/drive_push.go
Introduces --if-exists=smart constant, extends local metadata with ModTime field, implements drivePushShouldSkipSmart helper comparing remote modified_time to local timestamp with safe fallback to upload, adds drivePushEnsureParentToken helper for nested uploads, and documents smart behavior in flag/tip/dry-run text.
Push smart and nested tests
shortcuts/drive/drive_push_test.go
Validates that nested file overwrites use the correct parent folder token in the multipart upload request.
Status quick detection mode
shortcuts/drive/drive_status.go
Adds --quick flag for modified-time-only comparison; refactors local walk to return ModTime metadata; implements precision-aware modified-time comparison; updates output to include detection field (exact|quick).
Status quick mode test coverage
shortcuts/drive/drive_status_test.go
Adds tests for quick-mode categorization by modified_time, validates untrusted timestamp handling, and asserts detection field in output.
Sync bidirectional command
shortcuts/drive/drive_sync.go
New +sync shortcut performs two-way sync: diffs local/remote using exact or quick detection, pulls new remote files, pushes new local files, and resolves modified conflicts via --on-conflict strategies (remote-wins, local-wins, keep-both with rename+rollback, interactive ask).
Sync comprehensive tests
shortcuts/drive/drive_sync_test.go
Extensive end-to-end coverage: all conflict resolution strategies, keep-both rollback on failure, ask-conflict EOF handling, duplicate-remote resolution, nested overwrites, new-local disappearance during sync, and quick-mode behavior.
Shortcut registration and documentation
shortcuts/drive/shortcuts.go, shortcuts_test.go, skills/lark-drive/SKILL.md, skills/lark-drive/references/lark-drive-push.md, lark-drive-status.md
Adds DriveSync to exported shortcut list; updates shortcut table documenting quick detection and sync command; extends push/status reference docs with smart mode semantics, examples, schema, and performance notes.
CLI end-to-end validation tests
tests/cli_e2e/drive/drive_status_dryrun_test.go, drive_status_workflow_test.go
Adds dry-run test for +status --quick, extends workflow test with quick-mode assertions, introduces dedicated workflow test with byte/timestamp-divergence fixture (using os.Chtimes), and adds helpers to parse Drive epoch strings (magnitude-based unit inference) and assert bucket contents via gjson.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • larksuite/cli#859: Introduces the core epoch parsing and time-comparison helpers (parseDriveEpoch, compareDriveRemoteModifiedToLocal) that are used by the smart-mode skip logic in this PR's pull and push implementations.
  • larksuite/cli#692: Refactors the underlying DriveStatus diff classification and output schema that this PR extends with the new --quick detection mode and detection field.
  • larksuite/cli#709: Implements the core drive +push shortcut and its --if-exists/upload mechanics that this PR enhances with smart timestamp-based skipping and parent-token handling.

Suggested labels

size/XL, feature/drive, kind/enhancement

Suggested reviewers

  • wittam-01

Poem

🐰 With whiskers twitching, smart sync hops,
Quick detection: timestamps, no downloads.
Two-way sync keeps both local and remote,
Rename, rollback, ask—never loses a note!
Incremental syncing: efficient and fast.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(drive): add +sync for two-way local/Drive sync' clearly and concisely describes the main feature addition—a new +sync command for two-way synchronization between local directories and Drive folders.
Description check ✅ Passed The PR description comprehensively covers all template sections with detailed information: a clear summary of the feature, a thorough list of included changes and capabilities, and a complete test plan with all verification steps completed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

❤️ Share

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

@github-actions github-actions Bot added domain/ccm PR touches the ccm domain size/L Large or sensitive change across domains or core paths labels May 14, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 91.43836% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.11%. Comparing base (5778adf) to head (72efad5).

Files with missing lines Patch % Lines
shortcuts/drive/drive_sync.go 91.40% 18 Missing and 7 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #873      +/-   ##
==========================================
+ Coverage   65.92%   66.11%   +0.19%     
==========================================
  Files         523      524       +1     
  Lines       49687    49979     +292     
==========================================
+ Hits        32757    33045     +288     
- Misses      14131    14136       +5     
+ Partials     2799     2798       -1     

☔ View full report in Codecov by Sentry.
📢 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
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/cli_e2e/drive/drive_status_workflow_test.go (1)

412-426: 💤 Low value

Consider importing epoch parsing logic from production code.

The mustParseDriveEpochForE2E helper duplicates the resolution-inference logic that exists in the production codebase (layer 1: epoch parsing helpers in shortcuts/drive/list_remote.go). While test-specific helpers are valuable for isolation, if the production parsing function is exported, importing it would reduce duplication and ensure consistency.

However, this duplication is acceptable for E2E test clarity and independence, so this is purely an optional refactor.

🤖 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/drive/drive_status_workflow_test.go` around lines 412 - 426,
The helper mustParseDriveEpochForE2E duplicates epoch resolution logic; replace
its logic by calling the production parsing helper (the exported epoch parse
function used in shortcuts/drive/list_remote.go) instead of reimplementing it:
update mustParseDriveEpochForE2E to invoke that exported function (or import and
use it directly in the test) so tests use the canonical parsing implementation
and avoid duplication while preserving the same error handling behavior.
🤖 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_pull.go`:
- Around line 332-343: In drivePullApplyRemoteModifiedTime, treat os.Chtimes
failures as best-effort: instead of returning an error after os.Chtimes fails,
log a warning containing the error and continue (return nil) so a successful
content download is not marked failed; update the os.Chtimes error branch in
drivePullApplyRemoteModifiedTime (which follows ResolvePath and uses os.Chtimes)
to emit a warning (e.g., output.Warnf or equivalent logger) mentioning that
preserving remote modified_time failed and include err, then return nil.

In `@shortcuts/drive/drive_sync.go`:
- Around line 323-345: The current conflict-handling branch renames the local
file (os.Rename using oldAbsPath -> newAbsPath with suffixedRel) before calling
drivePullDownload, risking loss of the original path if the download fails;
change the flow to either (A) download the remote file to a temporary path
(e.g., under the same directory) and only rename/move it into entry.RelPath
after drivePullDownload succeeds, or (B) if you must rename first, perform the
rename as you do now (oldAbsPath -> newAbsPath) but on drivePullDownload failure
rollback by renaming newAbsPath back to oldAbsPath and record the failure;
update items (driveSyncItem) consistently in both success and rollback paths and
ensure you reference pullRemoteFiles[entry.RelPath], drivePullDownload,
oldAbsPath/newAbsPath, and suffixedRel when making the change.
- Around line 395-408: driveSyncAskConflict currently ignores Fscanln errors and
treats empty answers as "remote-wins"; change the input handling to capture and
check the error from fmt.Fscanln in driveSyncAskConflict, and on any read
failure (err != nil) print a brief diagnostic to runtime.IO().ErrOut and return
the skip outcome (empty string) or propagate an error instead of falling through
to the default remote-wins branch; only proceed to TrimSpace/ToLower and the
switch when Fscanln succeeded so that the default case remains remote-wins for
valid empty input but not for unreadable stdin. Ensure you modify the call site
using fmt.Fscanln to capture the error and reference driveSyncAskConflict,
runtime.IO(), and the existing return values
driveSyncOnConflictRemoteWins/KeepBoth/LocalWins to locate the code.

In `@skills/lark-drive/SKILL.md`:
- Line 232: The inline code token `detection=exact|quick` inside the table cell
is breaking the Markdown table because the pipe is parsed as a column separator;
update that token to escape the pipe (e.g., change to `detection=exact\|quick`)
or wrap the whole cell content in a code span that preserves the literal pipe so
the table renders correctly; locate the occurrence of the literal string
detection=exact|quick in SKILL.md and apply the escape so the table columns
remain intact.

---

Nitpick comments:
In `@tests/cli_e2e/drive/drive_status_workflow_test.go`:
- Around line 412-426: The helper mustParseDriveEpochForE2E duplicates epoch
resolution logic; replace its logic by calling the production parsing helper
(the exported epoch parse function used in shortcuts/drive/list_remote.go)
instead of reimplementing it: update mustParseDriveEpochForE2E to invoke that
exported function (or import and use it directly in the test) so tests use the
canonical parsing implementation and avoid duplication while preserving the same
error handling behavior.
🪄 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: 1290dfb2-d131-4917-8e32-de7866021c71

📥 Commits

Reviewing files that changed from the base of the PR and between a18504b and 48c29ed.

📒 Files selected for processing (20)
  • shortcuts/drive/drive_duplicate_remote_test.go
  • shortcuts/drive/drive_pull.go
  • shortcuts/drive/drive_pull_test.go
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_push_test.go
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_sync_test.go
  • shortcuts/drive/list_remote.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-pull.md
  • skills/lark-drive/references/lark-drive-push.md
  • skills/lark-drive/references/lark-drive-status.md
  • tests/cli_e2e/drive/drive_pull_dryrun_test.go
  • tests/cli_e2e/drive/drive_push_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_workflow_test.go

Comment thread shortcuts/drive/drive_pull.go
Comment thread shortcuts/drive/drive_sync.go
Comment thread shortcuts/drive/drive_sync.go Outdated
Comment thread skills/lark-drive/SKILL.md Outdated
@fangshuyu-768 fangshuyu-768 changed the title feat(drive): add +sync command for two-way sync between local and Drive feat(drive): add +sync for two-way local/Drive sync May 14, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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)
skills/lark-drive/SKILL.md (1)

232-234: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape | inside inline code to keep the shortcuts table valid.

Line 232 and Line 234 contain unescaped pipes inside table cells, which breaks column parsing in Markdown renderers.

Suggested fix
-| [`+status`](references/lark-drive-status.md) | Compare a local directory with a Drive folder by exact SHA-256 hash by default, or use `--quick` for a best-effort modified-time diff that skips remote downloads; reports `new_local` / `new_remote` / `modified` / `unchanged` plus `detection=exact|quick`. Duplicate remote `rel_path` conflicts fail fast with `error.type=duplicate_remote_path` and list every conflicting entry; do not proceed as if one was chosen. `--local-dir` 必须是 cwd 内的相对路径,越界路径 CLI 会直接拒绝;目标在 cwd 外时引导用户切换 agent 工作目录,不要私自 `cd` 绕过。 |
+| [`+status`](references/lark-drive-status.md) | Compare a local directory with a Drive folder by exact SHA-256 hash by default, or use `--quick` for a best-effort modified-time diff that skips remote downloads; reports `new_local` / `new_remote` / `modified` / `unchanged` plus `detection=exact\|quick`. Duplicate remote `rel_path` conflicts fail fast with `error.type=duplicate_remote_path` and list every conflicting entry; do not proceed as if one was chosen. `--local-dir` 必须是 cwd 内的相对路径,越界路径 CLI 会直接拒绝;目标在 cwd 外时引导用户切换 agent 工作目录,不要私自 `cd` 绕过。 |
-| `+sync` | Two-way local ↔ Drive sync. Reuses `+status` diff buckets, pulls `new_remote`, pushes `new_local`, and resolves `modified` via `--on-conflict=remote-wins|local-wins|keep-both|ask`. `--quick` enables modified-time diffing, `--on-duplicate-remote` supports `fail|newest|oldest`, and the command is intentionally non-destructive (no delete on either side). |
+| `+sync` | Two-way local ↔ Drive sync. Reuses `+status` diff buckets, pulls `new_remote`, pushes `new_local`, and resolves `modified` via `--on-conflict=remote-wins\|local-wins\|keep-both\|ask`. `--quick` enables modified-time diffing, `--on-duplicate-remote` supports `fail\|newest\|oldest`, and the command is intentionally non-destructive (no delete on either side). |
🤖 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-drive/SKILL.md` around lines 232 - 234, Table cells in SKILL.md
contain unescaped pipe characters inside inline code which breaks Markdown table
parsing; locate the inline code tokens in the table for `+status`
(`detection=exact|quick`), `+sync`
(`--on-conflict=remote-wins|local-wins|keep-both|ask`) and `+sync`/`+pull` spots
with option enumerations (e.g. `--on-duplicate-remote` values
`fail|newest|oldest`) and escape every `|` as `\|` (or alternatively wrap the
entire cell in a code span/block) so the pipes are treated literally and the
table columns render correctly.
🤖 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_sync_test.go`:
- Around line 612-614: The test currently slices out using strings.Index without
checking the result which can panic if `"items"` is missing; change the logic in
the test around the itemsSection creation (the code using strings.Index(out,
`"items"`) and variable itemsSection) to first capture the index,
assert/index-check it is >= 0 (e.g. t.Fatalf/t.Errorf including the full output
if missing), and only then slice out[idx:] and run the existing containment
assertion for `"rel_path": "a.txt"`.

---

Duplicate comments:
In `@skills/lark-drive/SKILL.md`:
- Around line 232-234: Table cells in SKILL.md contain unescaped pipe characters
inside inline code which breaks Markdown table parsing; locate the inline code
tokens in the table for `+status` (`detection=exact|quick`), `+sync`
(`--on-conflict=remote-wins|local-wins|keep-both|ask`) and `+sync`/`+pull` spots
with option enumerations (e.g. `--on-duplicate-remote` values
`fail|newest|oldest`) and escape every `|` as `\|` (or alternatively wrap the
entire cell in a code span/block) so the pipes are treated literally and the
table columns render correctly.
🪄 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: fa906003-d31e-4652-b217-a8e90b8bd977

📥 Commits

Reviewing files that changed from the base of the PR and between 48c29ed and d319297.

📒 Files selected for processing (3)
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_sync_test.go
  • skills/lark-drive/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/drive/drive_sync.go

Comment on lines +612 to +614
itemsSection := out[strings.Index(out, `"items"`):]
if strings.Contains(itemsSection, `"rel_path": "a.txt"`) {
t.Errorf("a.txt should not appear in items[] (mtime matches remote, should be unchanged)\noutput: %s", out)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard the items section lookup before slicing.

Line 612 can panic when "items" is missing, which makes failures less diagnosable than a normal test assertion.

Suggested fix
-	itemsSection := out[strings.Index(out, `"items"`):]
+	idx := strings.Index(out, `"items"`)
+	if idx == -1 {
+		t.Fatalf(`expected "items" section in output, got: %s`, out)
+	}
+	itemsSection := out[idx:]
 	if strings.Contains(itemsSection, `"rel_path": "a.txt"`) {
 		t.Errorf("a.txt should not appear in items[] (mtime matches remote, should be unchanged)\noutput: %s", out)
 	}
📝 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
itemsSection := out[strings.Index(out, `"items"`):]
if strings.Contains(itemsSection, `"rel_path": "a.txt"`) {
t.Errorf("a.txt should not appear in items[] (mtime matches remote, should be unchanged)\noutput: %s", out)
idx := strings.Index(out, `"items"`)
if idx == -1 {
t.Fatalf(`expected "items" section in output, got: %s`, out)
}
itemsSection := out[idx:]
if strings.Contains(itemsSection, `"rel_path": "a.txt"`) {
t.Errorf("a.txt should not appear in items[] (mtime matches remote, should be unchanged)\noutput: %s", out)
}
🤖 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_sync_test.go` around lines 612 - 614, The test
currently slices out using strings.Index without checking the result which can
panic if `"items"` is missing; change the logic in the test around the
itemsSection creation (the code using strings.Index(out, `"items"`) and variable
itemsSection) to first capture the index, assert/index-check it is >= 0 (e.g.
t.Fatalf/t.Errorf including the full output if missing), and only then slice
out[idx:] and run the existing containment assertion for `"rel_path": "a.txt"`.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
skills/lark-drive/SKILL.md (1)

232-232: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape | in inline code inside the shortcuts table.

Line 232 and Line 234 use unescaped pipes in inline code, which breaks table column parsing (MD056). Escape each | as \|.

Suggested fix
-| [`+status`](references/lark-drive-status.md) | Compare a local directory with a Drive folder by exact SHA-256 hash by default, or use `--quick` for a best-effort modified-time diff that skips remote downloads; reports `new_local` / `new_remote` / `modified` / `unchanged` plus `detection=exact|quick`. Duplicate remote `rel_path` conflicts fail fast with `error.type=duplicate_remote_path` and list every conflicting entry; do not proceed as if one was chosen. `--local-dir` 必须是 cwd 内的相对路径,越界路径 CLI 会直接拒绝;目标在 cwd 外时引导用户切换 agent 工作目录,不要私自 `cd` 绕过。 |
+| [`+status`](references/lark-drive-status.md) | Compare a local directory with a Drive folder by exact SHA-256 hash by default, or use `--quick` for a best-effort modified-time diff that skips remote downloads; reports `new_local` / `new_remote` / `modified` / `unchanged` plus `detection=exact\|quick`. Duplicate remote `rel_path` conflicts fail fast with `error.type=duplicate_remote_path` and list every conflicting entry; do not proceed as if one was chosen. `--local-dir` 必须是 cwd 内的相对路径,越界路径 CLI 会直接拒绝;目标在 cwd 外时引导用户切换 agent 工作目录,不要私自 `cd` 绕过。 |
-| `+sync` | Two-way local ↔ Drive sync. Reuses `+status` diff buckets, pulls `new_remote`, pushes `new_local`, and resolves `modified` via `--on-conflict=remote-wins|local-wins|keep-both|ask`. `--quick` enables best-effort modified-time diffing (timestamp mismatches can still trigger real pull/push actions), `--on-duplicate-remote` supports `fail|newest|oldest`, and the command is intentionally non-destructive (no delete on either side). |
+| `+sync` | Two-way local ↔ Drive sync. Reuses `+status` diff buckets, pulls `new_remote`, pushes `new_local`, and resolves `modified` via `--on-conflict=remote-wins\|local-wins\|keep-both\|ask`. `--quick` enables best-effort modified-time diffing (timestamp mismatches can still trigger real pull/push actions), `--on-duplicate-remote` supports `fail\|newest\|oldest`, and the command is intentionally non-destructive (no delete on either side). |

Also applies to: 234-234

🤖 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-drive/SKILL.md` at line 232, The table row containing the
`+status` shortcut has inline code spans that include pipe characters which
break Markdown table parsing (e.g., `detection=exact|quick`,
`error.type=duplicate_remote_path`,
`new_local`/`new_remote`/`modified`/`unchanged` and flags like
`--quick`/`--local-dir`); update the SKILL.md row text so every literal pipe
within inline code is escaped as `\|` (for example change
`detection=exact|quick` to `detection=exact\|quick`) throughout the `+status`
row and any nearby rows (including the similar occurrence around line 234) so
the Markdown table renders properly.
shortcuts/drive/drive_sync_test.go (1)

752-755: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard the items section lookup before slicing.

Line 752 can produce confusing test results when "items" is missing from the output. If strings.Index returns -1, out[-1:] slices from the end, causing the subsequent strings.Contains check to search the entire string instead of just the items section, which makes test failures less diagnosable.

Suggested fix
-	itemsSection := out[strings.Index(out, `"items"`):]
+	idx := strings.Index(out, `"items"`)
+	if idx == -1 {
+		t.Fatalf(`expected "items" section in output, got: %s`, out)
+	}
+	itemsSection := out[idx:]
 	if strings.Contains(itemsSection, `"rel_path": "a.txt"`) {
 		t.Errorf("a.txt should not appear in items[] (mtime matches remote, should be unchanged)\noutput: %s", out)
 	}
🤖 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_sync_test.go` around lines 752 - 755, The test
currently slices out using strings.Index(out, `"items"`) without checking for -1
which can produce an unintended slice when `"items"` is absent; fix by checking
the index first (e.g., idx := strings.Index(out, `"items"`)) and fail the test
or return immediately with a clear error if idx == -1, otherwise compute
itemsSection := out[idx:] and then run the existing strings.Contains check for
`"rel_path": "a.txt"`; reference the existing symbols itemsSection, out,
strings.Index and strings.Contains when applying this guard.
🤖 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.

Duplicate comments:
In `@shortcuts/drive/drive_sync_test.go`:
- Around line 752-755: The test currently slices out using strings.Index(out,
`"items"`) without checking for -1 which can produce an unintended slice when
`"items"` is absent; fix by checking the index first (e.g., idx :=
strings.Index(out, `"items"`)) and fail the test or return immediately with a
clear error if idx == -1, otherwise compute itemsSection := out[idx:] and then
run the existing strings.Contains check for `"rel_path": "a.txt"`; reference the
existing symbols itemsSection, out, strings.Index and strings.Contains when
applying this guard.

In `@skills/lark-drive/SKILL.md`:
- Line 232: The table row containing the `+status` shortcut has inline code
spans that include pipe characters which break Markdown table parsing (e.g.,
`detection=exact|quick`, `error.type=duplicate_remote_path`,
`new_local`/`new_remote`/`modified`/`unchanged` and flags like
`--quick`/`--local-dir`); update the SKILL.md row text so every literal pipe
within inline code is escaped as `\|` (for example change
`detection=exact|quick` to `detection=exact\|quick`) throughout the `+status`
row and any nearby rows (including the similar occurrence around line 234) so
the Markdown table renders properly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3abea75e-7c76-4004-acd0-2069aeec3e5c

📥 Commits

Reviewing files that changed from the base of the PR and between d319297 and be2ac35.

📒 Files selected for processing (5)
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_push_test.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_sync_test.go
  • skills/lark-drive/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_push_test.go

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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`:
- Line 234: The table cell for `+sync` contains unescaped pipe characters in
option examples (e.g., `--on-conflict=...` and
`--on-duplicate-remote=fail|newest|oldest`) which breaks Markdown table parsing;
update the `+sync` row so any `|` inside inline code is escaped (e.g., `\|` or
HTML entity `|`) or wrap the entire option list in a protected code span so
`--on-conflict`, `--on-duplicate-remote` and the `fail|newest|oldest` example
render as a single table cell without splitting columns.
🪄 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: e0816faf-fad9-44bb-9c24-6b170d45aae9

📥 Commits

Reviewing files that changed from the base of the PR and between be2ac35 and ee47bb8.

📒 Files selected for processing (20)
  • shortcuts/drive/drive_duplicate_remote_test.go
  • shortcuts/drive/drive_pull.go
  • shortcuts/drive/drive_pull_test.go
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_push_test.go
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_sync_test.go
  • shortcuts/drive/list_remote.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-pull.md
  • skills/lark-drive/references/lark-drive-push.md
  • skills/lark-drive/references/lark-drive-status.md
  • tests/cli_e2e/drive/drive_pull_dryrun_test.go
  • tests/cli_e2e/drive/drive_push_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_workflow_test.go
✅ Files skipped from review due to trivial changes (3)
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/references/lark-drive-pull.md
  • skills/lark-drive/references/lark-drive-status.md
🚧 Files skipped from review as they are similar to previous changes (13)
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/list_remote.go
  • shortcuts/drive/drive_duplicate_remote_test.go
  • tests/cli_e2e/drive/drive_push_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_dryrun_test.go
  • skills/lark-drive/references/lark-drive-push.md
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • tests/cli_e2e/drive/drive_status_workflow_test.go
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_pull.go
  • shortcuts/drive/drive_sync_test.go

Comment thread skills/lark-drive/SKILL.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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/references/lark-drive-push.md`:
- Line 70: The doc contains duplicated entries for the `--if-exists` option (the
table row, bullet list entries, and the "smart" mode paragraph are repeated);
remove the duplicate occurrences so there is only one canonical description of
`--if-exists` and its enum values (`skip`, `smart`, `overwrite`) and keep a
single explanatory paragraph for the "smart" mode — update the sections that
reference `--if-exists` (including the repeated table row and the repeated
smart-mode paragraph) to eliminate redundancy while preserving the single
authoritative wording.
🪄 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: d82c44a8-4dfd-429d-882c-d6ba3e9b7bdc

📥 Commits

Reviewing files that changed from the base of the PR and between ee47bb8 and 2ae9e3a.

📒 Files selected for processing (14)
  • shortcuts/drive/drive_pull_test.go
  • shortcuts/drive/drive_push.go
  • shortcuts/drive/drive_push_test.go
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_sync_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-push.md
  • skills/lark-drive/references/lark-drive-status.md
  • tests/cli_e2e/drive/drive_status_dryrun_test.go
  • tests/cli_e2e/drive/drive_status_workflow_test.go
💤 Files with no reviewable changes (1)
  • shortcuts/drive/drive_pull_test.go
✅ Files skipped from review due to trivial changes (1)
  • skills/lark-drive/references/lark-drive-status.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • shortcuts/drive/shortcuts_test.go
  • shortcuts/drive/shortcuts.go
  • tests/cli_e2e/drive/drive_status_dryrun_test.go
  • shortcuts/drive/drive_sync.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/drive_status.go
  • tests/cli_e2e/drive/drive_status_workflow_test.go
  • shortcuts/drive/drive_sync_test.go

Comment thread skills/lark-drive/references/lark-drive-push.md Outdated
@fangshuyu-768 fangshuyu-768 force-pushed the feat/drive-sync branch 2 times, most recently from f4c18cd to 40850c7 Compare May 15, 2026 11:08
Add a dedicated drive +sync shortcut so repeated local/remote directory syncs can be handled in one workflow with explicit conflict policies and stronger coverage for shared diff logic.
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/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