Skip to content

feat(drive): add +status shortcut for content-hash diff#692

Merged
wittam-01 merged 6 commits intomainfrom
feat/drive-status
Apr 30, 2026
Merged

feat(drive): add +status shortcut for content-hash diff#692
wittam-01 merged 6 commits intomainfrom
feat/drive-status

Conversation

@fangshuyu-768
Copy link
Copy Markdown
Collaborator

@fangshuyu-768 fangshuyu-768 commented Apr 28, 2026

Summary

Adds a new drive +status shortcut: a read-only diff primitive that walks --local-dir, recursively lists --folder-token, and reports four buckets by SHA-256 content hash.

  • new_local — only in --local-dir
  • new_remote — only under --folder-token
  • modified — both sides exist, hashes differ
  • unchanged — both sides exist, hashes match

Designed as the foundation any future +push / +pull / +sync workflow can build on.

Design notes

  • SHA-256 streamed in memory. Drive's list/metas APIs do not expose a content hash, so files present on both sides are downloaded via GET /open-apis/drive/v1/files/:file_token/download and hashed via io.Copy(sha256.New(), resp.Body) — never written to disk. Files only on one side are not fetched. Command stays Risk: "read".
  • type=file only. Online docs (docx / sheet / bitable / mindnote / slides) and shortcuts are skipped because there is no equivalent local binary to hash against. Subfolders recurse via the standard list pagination loop.
  • --local-dir is bounded by cwd through three layers: (1) the framework's validate.SafeLocalFlagPath("--local-dir", ...) runs first so the error message references the correct flag name; (2) runtime.FileIO().Stat re-applies SafeInputPath for existence + IsDir checks; (3) per-file runtime.FileIO().Open during walk. Absolute paths and any .. that escapes cwd are rejected with structured validation errors.
  • filepath.WalkDir is annotated with //nolint:forbidigo. Shortcuts can't import internal/vfs and the runtime FileIO interface has no walker today; the bare walk is fine here because SafeInputPath has already bounded the root. Worth replacing once a runtime-level walker lands.
  • Scopes: drive:drive.metadata:readonly (list folders) + drive:file:download (fetch files for hashing). The broader drive:drive is disabled by enterprise policy in some tenants; the narrower pair was verified end-to-end.

Output shape

{
  "new_local":  [{"rel_path": "..."}],
  "new_remote": [{"rel_path": "...", "file_token": "..."}],
  "modified":   [{"rel_path": "...", "file_token": "..."}],
  "unchanged":  [{"rel_path": "...", "file_token": "..."}]
}

Test plan

A. Static checks

# Check Result
A1 go build ./... ✅ no output
A2 go vet ./... ✅ no output
A3 golangci-lint run --new-from-rev=origin/main ./shortcuts/drive/... ✅ 0 issues (only nolint:forbidigo on the walker, with comment)
A4 node scripts/skill-format-check/index.js skills ✅ Skill format check passed
A5 Full non-e2e suite: `go test $(go list ./... grep -v cli_e2e) -count=1`
A6 CI (latest force-push) ✅ 21/21 checks green

B. Unit tests (go test ./shortcuts/drive/... -run TestDriveStatus)

# Test Coverage
B1 TestDriveStatusCategorizesByHash All 4 buckets in one run with a nested subfolder; verifies docx and shortcut entries are skipped
B2 TestDriveStatusRejectsMissingLocalDir --local-dir points at a path that doesn't exist → validation error
B3 TestDriveStatusRejectsLocalFile --local-dir points at a regular file → "is not a directory" error
B4 TestDriveStatusRejectsAbsoluteLocalDir --local-dir /etc → SafeInputPath rejection
B5 TestShortcutsIncludesExpectedCommands Registry includes +status

C. End-to-end against a real Drive folder (happy path)

Local tree (10 files, 7 directories) ↔ remote tree (9 files, 4 directories):

Bucket Count Items
modified 3 conflict.txt, docs/changelog.md, docs/中文文档.md
unchanged 3 docs/readme.md, images/logo.bin (binary), stub.txt (1 byte)
new_local 4 deeply/nested/path/deep.txt (4-level nesting), empty-local-only.txt (0 bytes), images/new-icon.bin, shared/notes.txt
new_remote 3 archive/2025-summary.md (remote-only subdir), docs/deprecated.md, images/old-icon.bin
  • ✅ Total 13 items classified, no double-bucketing
  • ✅ Each bucket sorted by rel_path (lexicographic)
  • ✅ Multilingual paths (docs/中文文档.md) round-trip without mojibake
  • ✅ Binary content (PNG header + payload in images/logo.bin) hashes identically on both sides → unchanged
  • ✅ 0-byte file (empty-local-only.txt) doesn't crash the hasher; correctly placed in new_local
  • ✅ 4-level nested path (deeply/nested/path/deep.txt) recurses correctly
  • ✅ Remote-only subdirectory (archive/) surfaces all its files in new_remote
  • ✅ Local-only subdirectories (shared/, deeply/) don't make remote API calls

D. --local-dir path variants (all real binary)

# Input Result
D1 local/ (trailing slash) ✅ accepted, 13 items
D2 ./local (dot-slash prefix) ✅ accepted, 13 items
D3 . (cwd itself) ✅ accepted, walks all of cwd

E. Path validation errors (real binary)

All return structured validation errors with the --local-dir flag name in the message (not the framework default --file):

# Input Error type Snippet
E1 --local-dir /etc validation --local-dir: --file must be a relative path within the current directory, got "/etc"
E2 --local-dir ../escape validation --local-dir: --file "../escape" resolves outside the current working directory
E3 --local-dir does-not-exist validation cannot read file: stat .../does-not-exist: no such file or directory
E4 --local-dir notadir.txt (regular file) validation --local-dir is not a directory: notadir.txt
E5 --local-dir $'lo\ncal' (newline char in name) validation resolves to a non-existent path → cannot read file: stat ...: no such file or directory (newline is a legal Unix filename char, so the path itself is well-formed and the error comes from the missing target)

F. Required / token validation

# Input Result
F1 omit --local-dir cobra: Error: required flag(s) "local-dir" not set
F2 omit --folder-token cobra: Error: required flag(s) "folder-token" not set
F3 --local-dir "" validation: --local-dir is required
F4 --folder-token "" validation: --folder-token is required
F5 --folder-token "tok\nwithnewline" validation: --folder-token contains invalid characters
F6 --folder-token "BOGUS_TOKEN_xxxxx" (passes format, fails API) api_error code 1061002 surfaced through structured envelope with log_id and troubleshooter URL
F7 Missing scope (initial drive:drive attempt before scope narrowing) missing_scope with auth login hint — confirms framework checks token scopes before issuing the API call

G. Dry-run

# Test Result
G1 --dry-run ✅ Prints description + GET /open-apis/drive/v1/files + folder_token summary; no real API calls

H. Output schema

# Check Result
H1 Top-level envelope keys {ok, identity, data}
H2 Data keys {new_local, new_remote, modified, unchanged}
H3 new_local[*] schema {rel_path} (no file_token, since the file isn't in Drive)
H4 new_remote / modified / unchanged[*] schema {rel_path, file_token}
H5 rel_path separator always forward-slash regardless of OS path style

@github-actions github-actions Bot added domain/ccm PR touches the ccm domain size/M Single-domain feat or fix with limited business impact labels Apr 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 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

Adds a new drive +status shortcut that compares a provided local manifest of files (relative to --local-dir) against a Drive folder (--folder-token) using SHA‑256 hashes, classifying files into new_local, new_remote, modified, and unchanged, and emitting JSON results.

Changes

Cohort / File(s) Summary
New Shortcut Implementation
shortcuts/drive/drive_status.go
Introduces exported DriveStatus command. Validates --local-dir, --folder-token, and non-empty --files-from. Normalizes/de‑dupes manifest paths, hashes local files (SHA‑256), recursively lists Drive files (paginated), downloads remote files for hashing, and emits JSON buckets: new_local, new_remote (with file_token), modified, unchanged. Dry-run returns Drive-listing shape; runtime prints progress to stderr.
Tests for Shortcut
shortcuts/drive/drive_status_test.go
Adds unit tests using temp files and HTTP stubs for Drive listing/download. Verifies classification buckets and tokens, ignores non‑file Drive entries, and checks validation errors for missing/non-directory --local-dir and blank --files-from. Includes tests for normalizeManifestPath.
Registry Update & Test
shortcuts/drive/shortcuts.go, shortcuts/drive/shortcuts_test.go
Registers DriveStatus in the drive shortcuts registry and updates the registry test to expect +status.
Documentation
skills/lark-drive/SKILL.md, skills/lark-drive/references/lark-drive-status.md
Adds documentation for drive +status: behavior, input rules (manifest normalization, no local tree walk), output JSON shape, Drive traversal rules (only type=file), required OAuth scopes, and usage examples/notes on network impact.

Sequence Diagram

sequenceDiagram
    participant User
    participant Cmd as "drive +status"
    participant LocalFS as "Local Filesystem"
    participant DriveAPI as "Drive API"
    participant Hasher as "SHA-256 Hasher"

    User->>Cmd: run with --local-dir, --folder-token, --files-from
    Cmd->>Cmd: validate inputs
    Cmd->>LocalFS: read manifest lines -> open files
    LocalFS-->>Hasher: stream file bytes
    Hasher-->>Cmd: local hashes by rel_path

    Cmd->>DriveAPI: list folder contents (paginated, recursive)
    DriveAPI-->>Cmd: file entries (only type=="file")
    Cmd->>Cmd: map remote rel_path -> file_token

    loop for each rel_path in intersection
        Cmd->>DriveAPI: download remote file (file_token)
        DriveAPI-->>Hasher: stream remote bytes
        Hasher-->>Cmd: remote hash
        Cmd->>Cmd: compare -> modified / unchanged
    end

    Cmd->>Cmd: mark new_local and new_remote
    Cmd-->>User: output JSON {new_local,new_remote,modified,unchanged}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • liujinkun2025

Poem

🐰 I hop through paths, I sniff each file's tone,
I hash the bytes where seeds of truth are sown,
I match the cloud with what sits on the ground,
I mark what's new, what's changed, what's safe and sound,
A tiny rabbit keeping file lists known.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: a new drive +status shortcut that performs content-hash-based differentiation between local files and a Drive folder.
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.
Description check ✅ Passed The PR description comprehensively covers all required template sections: summary, changes, test plan with checkboxes and detailed coverage, and related issues. Exceeds minimum requirements with extensive design notes, output schema, and validation test matrix.

✏️ 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-status

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 73.17073% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.83%. Comparing base (0bbd0f2) to head (ac67edf).
⚠️ Report is 19 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/drive/drive_status.go 73.00% 25 Missing and 19 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #692      +/-   ##
==========================================
+ Coverage   63.55%   63.83%   +0.27%     
==========================================
  Files         497      501       +4     
  Lines       42455    43695    +1240     
==========================================
+ Hits        26984    27893     +909     
- Misses      13129    13342     +213     
- Partials     2342     2460     +118     

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

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

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

8-47: Consider asserting the exact shortcut order.

This membership-only check will miss regressions where Shortcuts() returns the right set in the wrong order. If the registry order is user-visible, a slice-by-slice assertion would be safer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/drive/shortcuts_test.go` around lines 8 - 47, The test only checks
membership and misses order regressions; change
TestShortcutsIncludesExpectedCommands to assert the exact ordering by extracting
commands from Shortcuts() (use the existing got variable: iterate over got to
build a []string of commands) and compare that slice to want (e.g., with
reflect.DeepEqual or cmp.Diff) instead of only checking lengths and a map of
seen; keep the duplicate-check but replace the final membership loop with an
ordered slice equality assertion so the test fails if Shortcuts() returns the
correct items in the wrong order.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/drive/drive_status_test.go`:
- Around line 135-173: Add tests that exercise the folder-token validation path
for the DriveStatus command: create one test that omits --folder-token and
asserts mountAndRunDrive(DriveStatus, ["+status","--local-dir", tmpDir,
"--as","bot"], ...) returns a validation error, and another test that supplies
an invalid/ malformed --folder-token (e.g. empty string or bad format) and
asserts the error message mentions folder-token format; follow the pattern and
helpers used by TestDriveStatusRejectsMissingLocalDir and
TestDriveStatusRejectsLocalFile (use withDriveWorkingDir, mountAndRunDrive,
DriveStatus and the same argument style) so the new tests cover required and
format validation for --folder-token.

In `@shortcuts/drive/drive_status.go`:
- Around line 76-81: The DryRun endpoint for the Drive shortcut (the DryRun func
in drive_status.go) is missing a required E2E dry-run test; add a new dry-run
E2E test under tests/cli_e2e/dryrun/ (or the drive domain test dir) that
exercises the CLI in dry-run mode for this shortcut: invoke the CLI command with
--dry-run plus the same flags used by the DryRun implementation (e.g.,
--local-dir and --folder-token), assert the tool performs the expected dry-run
HTTP request to GET /open-apis/drive/v1/files with the folder_token query param,
and validate the dry-run output contains the descriptive text from Desc; follow
the existing dry-run test harness patterns in the repo for setup/teardown and
request assertions.

---

Nitpick comments:
In `@shortcuts/drive/shortcuts_test.go`:
- Around line 8-47: The test only checks membership and misses order
regressions; change TestShortcutsIncludesExpectedCommands to assert the exact
ordering by extracting commands from Shortcuts() (use the existing got variable:
iterate over got to build a []string of commands) and compare that slice to want
(e.g., with reflect.DeepEqual or cmp.Diff) instead of only checking lengths and
a map of seen; keep the duplicate-check but replace the final membership loop
with an ordered slice equality assertion so the test fails if Shortcuts()
returns the correct items in the wrong order.
🪄 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: 84a2de7a-6eff-4fe6-b431-b1a41e75310a

📥 Commits

Reviewing files that changed from the base of the PR and between 2e4cfb4 and 4ab562c.

📒 Files selected for processing (4)
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go

Comment thread shortcuts/drive/drive_status_test.go
Comment thread shortcuts/drive/drive_status.go
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

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

@github-actions github-actions Bot added size/L Large or sensitive change across domains or core paths and removed size/M Single-domain feat or fix with limited business impact labels Apr 28, 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.

♻️ Duplicate comments (1)
shortcuts/drive/drive_status.go (1)

75-80: ⚠️ Potential issue | 🟠 Major

Please confirm required dry-run E2E coverage for drive +status.

This shortcut adds new behavior and DryRun shape, but I can’t verify an accompanying dry-run E2E test from the provided diff context. Please confirm it exists under tests/cli_e2e/dryrun/ (or drive domain equivalent).

#!/bin/bash
# Check for dry-run E2E coverage of drive +status
fd -i '_test.go' tests/cli_e2e
rg -n --type=go --iglob '*_test.go' 'drive\s+\+status|--local-dir|--folder-token|--dry-run' tests/cli_e2e

Based on learnings "Dry-run E2E tests are required for every shortcut change; place in tests/cli_e2e/dryrun/ or corresponding domain directory".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/drive/drive_status.go` around lines 75 - 80, Add or confirm a
dry-run E2E test that covers the new DryRun shape for the drive +status
shortcut: create/verify a test under tests/cli_e2e/dryrun (or a drive domain
subdir) that invokes the CLI with drive +status and the flags --local-dir and
--folder-token and asserts the DryRun HTTP GET to /open-apis/drive/v1/files with
folder_token is produced; reference the DryRun function and its Desc text in
shortcuts/drive/drive_status.go to ensure the test exercises the exact dry-run
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@shortcuts/drive/drive_status.go`:
- Around line 75-80: Add or confirm a dry-run E2E test that covers the new
DryRun shape for the drive +status shortcut: create/verify a test under
tests/cli_e2e/dryrun (or a drive domain subdir) that invokes the CLI with drive
+status and the flags --local-dir and --folder-token and asserts the DryRun HTTP
GET to /open-apis/drive/v1/files with folder_token is produced; reference the
DryRun function and its Desc text in shortcuts/drive/drive_status.go to ensure
the test exercises the exact dry-run behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e8d7c01-362d-45b0-8ed1-68034e2f4bc1

📥 Commits

Reviewing files that changed from the base of the PR and between 1e57eea and ea6cd37.

📒 Files selected for processing (1)
  • shortcuts/drive/drive_status.go

@fangshuyu-768 fangshuyu-768 changed the title feat(drive): add +status shortcut for hash-based local↔Drive diff feat(drive): add +status shortcut for content-hash diff Apr 28, 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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/drive/drive_status.go`:
- Around line 206-209: The branch that now only checks strings.HasPrefix(p,
"../") should also reject a bare ".." when cleanRoot is non-empty: add a guard
that returns "" when p == ".." in the same conditional block so that callers
(e.g., where filepath.Join(cleanRoot, p) is used) don't get a stray ".."
returned; update the logic around the p variable in drive_status.go to mirror
the earlier check for p == ".." when cleanRoot == "." or "" so both cases
consistently reject directory traversal.
🪄 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: 2bdde10a-c4b2-459c-b78a-eeb886e9046f

📥 Commits

Reviewing files that changed from the base of the PR and between ea6cd37 and d23598f.

📒 Files selected for processing (6)
  • shortcuts/drive/drive_status.go
  • shortcuts/drive/drive_status_test.go
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
  • skills/lark-drive/references/lark-drive-status.md
✅ Files skipped from review due to trivial changes (3)
  • shortcuts/drive/shortcuts.go
  • shortcuts/drive/shortcuts_test.go
  • skills/lark-drive/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • shortcuts/drive/drive_status_test.go
  • skills/lark-drive/references/lark-drive-status.md

Comment thread shortcuts/drive/drive_status.go Outdated
@fangshuyu-768 fangshuyu-768 force-pushed the feat/drive-status branch 2 times, most recently from 37f6fb3 to 482485b Compare April 28, 2026 10:47
fangshuyu-768 added a commit that referenced this pull request Apr 28, 2026
Addresses two CodeRabbit review comments on PR #692:

- Adds TestDriveStatusRejectsEmptyFolderToken and
  TestDriveStatusRejectsMalformedFolderToken so the Validate-stage
  required-check and the ResourceName format guard for --folder-token
  are exercised, not just --local-dir.

- Adds tests/cli_e2e/drive/drive_status_dryrun_test.go which drives
  the real binary in dry-run mode and asserts:

  * the request shape (GET /open-apis/drive/v1/files with
    folder_token in the dry-run envelope), plus the description text,
  * --local-dir absolute paths are rejected by Validate (which still
    runs under --dry-run) with --local-dir surfaced in the message,
  * cobra's required-flag enforcement rejects a missing
    --folder-token before any custom validation.
Adds `drive +status`, a read-only diff primitive that walks --local-dir,
recursively lists --folder-token, and reports four buckets — new_local,
new_remote, modified, unchanged — by SHA-256 content hash.

Implementation notes:

- Drive's list/metas APIs do not expose a content hash, so files
  present on both sides are downloaded via DoAPIStream and hashed in
  memory (sha256 + io.Copy, no disk write). Files only on one side are
  not fetched. The command stays Risk: "read".

- Only Drive entries with type=file participate. Online docs (docx,
  sheet, bitable, mindnote, slides) and shortcuts are skipped — there
  is no equivalent local binary to hash against.

- --local-dir is funneled through the framework's
  validate.SafeLocalFlagPath helper so that absolute paths and any ..
  that escapes cwd are rejected with --local-dir in the error message
  (rather than the internal default --file). FileIO().Stat() then
  enforces existence and the IsDir check.

- Local walk uses filepath.WalkDir behind a //nolint:forbidigo comment.
  The runtime FileIO interface has no walker today and shortcuts can't
  import internal/vfs; SafeInputPath has already bounded the walk root
  inside cwd, so the bare walk is acceptable until a runtime-level
  walker lands.

- Scopes: drive:drive.metadata:readonly (list folders) +
  drive:file:download (fetch files for hashing). The broader
  drive:drive scope is disabled by enterprise policy in some tenants;
  this narrower pair was verified end-to-end.

Tests cover the four-bucket categorization with a nested subfolder and
docx/shortcut filtering, plus validation errors for missing local-dir,
non-directory local-dir, and absolute-path local-dir.
Adds references/lark-drive-status.md covering parameters, output
schema, the type=file scoping rule, and the network-traffic caveat
(hash is streamed in memory, but bytes still cross the wire).

Notes that --local-dir is bounded to cwd by the CLI's path validation,
and that when a user wants to compare a directory outside cwd the
agent should ask the user to relocate or to switch the agent's working
directory rather than `cd`-ing on its own.

Wires +status into the Shortcuts table in SKILL.md.
Addresses two CodeRabbit review comments on PR #692:

- Adds TestDriveStatusRejectsEmptyFolderToken and
  TestDriveStatusRejectsMalformedFolderToken so the Validate-stage
  required-check and the ResourceName format guard for --folder-token
  are exercised, not just --local-dir.

- Adds tests/cli_e2e/drive/drive_status_dryrun_test.go which drives
  the real binary in dry-run mode and asserts:

  * the request shape (GET /open-apis/drive/v1/files with
    folder_token in the dry-run envelope), plus the description text,
  * --local-dir absolute paths are rejected by Validate (which still
    runs under --dry-run) with --local-dir surfaced in the message,
  * cobra's required-flag enforcement rejects a missing
    --folder-token before any custom validation.
….. escape

Reported in PR review: --local-dir was validated through
SafeLocalFlagPath, but the actual walk used the user-supplied raw
string. SafeLocalFlagPath returns the original value (it only checks
the path through SafeInputPath and discards the canonical form), and
SafeInputPath itself relies on filepath.Clean for path normalization.
filepath.Clean shrinks "link/.." to "." purely as string manipulation,
so the validator sees a path inside cwd. The kernel, however, resolves
"link/.." through the symlink target's parent — which is outside cwd
and is what filepath.WalkDir actually traverses.

Fix: in Execute, resolve --local-dir via validate.SafeInputPath to
get the canonical absolute path (this one fully evaluates symlinks
across the entire path), and walk that path. Each absolute walk hit
is converted to a cwd-relative form via filepath.Rel against
validate.SafeInputPath(".") so FileIO.Open's existing SafeInputPath
guard (which rejects absolute paths) still applies.

Adds TestDriveStatusDoesNotEscapeViaSymlinkParentRef as a regression:
it stages an "escape" sibling directory containing a sentinel file,
adds a "link" symlink in cwd pointing into the escape directory, and
runs +status with --local-dir "link/..". Without this fix, the raw
walk visits the sentinel and leaks it into new_local; with the fix,
the walk stays inside the canonical cwd.

A standalone repro confirms the underlying behavior: raw
filepath.WalkDir("link/..", ...) traversed dozens of unrelated files
in the kernel-resolved parent directory; walking the canonical root
visits only the legitimate cwd contents.
…atus

Adds two corner-case regressions to back up the canonical-root walk fix:

- TestDriveStatusSkipsSymlinkInsideRoot: a child symlink under
  --local-dir that points to a sibling temp dir outside cwd. WalkDir's
  default policy must report it as a non-regular entry so the callback
  skips it, and the sentinel inside the target must not surface in
  new_local. This pins the contract our caller relies on (walk
  declines to follow child symlinks even when the canonical root
  resolves cleanly).

- TestDriveStatusSurvivesCircularSymlinkInsideRoot: a child symlink
  pointing back at one of its ancestors. The walk must terminate and
  surface the legitimate sibling file; if WalkDir ever followed the
  loop, the per-test timeout would catch it.
fangshuyu-768 added a commit that referenced this pull request Apr 28, 2026
Adds `drive +pull`, a one-way Drive → local mirror command. It
recursively lists --folder-token, downloads each type=file entry
into --local-dir at the matching relative path, and optionally
deletes local files absent from the remote (mirror semantics).

Implementation notes:

- Listing recurses through subfolders with the standard 200-page
  pagination loop. Online docs (docx, sheet, bitable, mindnote,
  slides) and shortcuts are skipped since there is no equivalent
  local binary to write back. Folder tree is reproduced under
  --local-dir, with parent directories auto-created by FileIO.Save.

- Per-file --if-exists=overwrite (default) | skip controls how
  pre-existing local files are treated; the framework's enum guard
  rejects any other value.

- --delete-local is the only destructive flag and is bound to --yes
  in Validate: --delete-local without --yes is rejected upfront so
  no listing or download even runs. --delete-local --yes performs
  downloads first, then walks --local-dir and removes regular files
  not present in the remote map. This matches the spec doc's
  "high-risk-write" intent for --delete-local without making the
  default pull path require confirmation.

- --local-dir is funneled through validate.SafeLocalFlagPath so
  errors reference --local-dir instead of the framework default
  --file. FileIO().Stat then enforces existence and IsDir.

- Scopes: drive:drive.metadata:readonly + drive:file:download. The
  broader drive:drive is disabled by enterprise policy in some
  tenants.

- Listing helper (drivePullListRemote) is duplicated locally rather
  than reused from drive_status.go because that change is still in
  open PR #692; once it merges, both can be lifted into a shared
  drive package helper. TODO marker is left in the code.

Tests cover six unit scenarios (happy-path with nested subfolder +
docx skipping, --if-exists=skip, --delete-local rejection without
--yes, --delete-local --yes deletes orphans, absolute-path
rejection, bad enum) and four E2E dry-run scenarios (request shape,
absolute path rejection, --delete-local --yes guard, missing
required flag).
…ve E2E)

Three independent fixes flagged on PR #692:

1. Route the recursive Drive folder listing through common.PaginationMeta
   instead of reading next_page_token directly. The shared helper accepts
   both page_token and next_page_token, matching what okr/im already do
   and keeping +status safe against a backend field rename. Adds
   TestDriveStatusPaginatesRemoteListing, which serves a 2-page response
   where page 1 advertises the cursor as next_page_token and page 2 as
   page_token; either spelling alone would silently drop one page.

2. The skill doc previously suggested "or symlink the target into cwd"
   as a workaround for cwd-relative --local-dir. SafeInputPath calls
   filepath.EvalSymlinks before checking isUnderDir(canonicalCwd), so
   any symlink whose final target sits outside cwd still gets rejected
   as `unsafe file path`. Rewrite the section so agents stop steering
   users into a path that always errors out.

3. Add tests/cli_e2e/drive/drive_status_workflow_test.go — the live
   E2E that AGENTS.md requires for new shortcuts. Seeds a real Drive
   folder with three uploaded files (unchanged.txt, modified.txt,
   remote-only.txt), seeds a local tree with matching/diverging
   content plus a local-only.txt, runs +status, and asserts each of
   the four buckets contains exactly the file we expect with the
   right file_token. Cleanup of every uploaded file plus the parent
   folder is registered through the existing best-effort cleanup
   helpers. Coverage table bumped: drive +status moves to ✓ and the
   denominator goes from 28→29 to account for the new shortcut.

Codex also flagged the local-side filepath.WalkDir as a vfs-bypass.
Investigated: the depguard rule shortcuts-no-vfs explicitly forbids
shortcuts from importing internal/vfs (see commit c1b0bed on the
+pull branch where the same migration was rejected by CI). The
filepath.WalkDir + nolint:forbidigo pattern in walkLocalForStatus is
the lint-required convention until FileIO grows a walker, so leaving
it as-is.
@wittam-01 wittam-01 merged commit a3bbe00 into main Apr 30, 2026
21 checks passed
@wittam-01 wittam-01 deleted the feat/drive-status branch April 30, 2026 06:27
fangshuyu-768 added a commit that referenced this pull request Apr 30, 2026
Adds `drive +pull`, a one-way Drive → local mirror command. It
recursively lists --folder-token, downloads each type=file entry
into --local-dir at the matching relative path, and optionally
deletes local files absent from the remote (mirror semantics).

Implementation notes:

- Listing recurses through subfolders with the standard 200-page
  pagination loop. Online docs (docx, sheet, bitable, mindnote,
  slides) and shortcuts are skipped since there is no equivalent
  local binary to write back. Folder tree is reproduced under
  --local-dir, with parent directories auto-created by FileIO.Save.

- Per-file --if-exists=overwrite (default) | skip controls how
  pre-existing local files are treated; the framework's enum guard
  rejects any other value.

- --delete-local is the only destructive flag and is bound to --yes
  in Validate: --delete-local without --yes is rejected upfront so
  no listing or download even runs. --delete-local --yes performs
  downloads first, then walks --local-dir and removes regular files
  not present in the remote map. This matches the spec doc's
  "high-risk-write" intent for --delete-local without making the
  default pull path require confirmation.

- --local-dir is funneled through validate.SafeLocalFlagPath so
  errors reference --local-dir instead of the framework default
  --file. FileIO().Stat then enforces existence and IsDir.

- Scopes: drive:drive.metadata:readonly + drive:file:download. The
  broader drive:drive is disabled by enterprise policy in some
  tenants.

- Listing helper (drivePullListRemote) is duplicated locally rather
  than reused from drive_status.go because that change is still in
  open PR #692; once it merges, both can be lifted into a shared
  drive package helper. TODO marker is left in the code.

Tests cover six unit scenarios (happy-path with nested subfolder +
docx skipping, --if-exists=skip, --delete-local rejection without
--yes, --delete-local --yes deletes orphans, absolute-path
rejection, bad enum) and four E2E dry-run scenarios (request shape,
absolute path rejection, --delete-local --yes guard, missing
required flag).
fangshuyu-768 added a commit that referenced this pull request Apr 30, 2026
…lder

Closes the post-#692 / post-#709 TODO that lived in drive_pull.go (and
the matching note in drive_push.go): both #692 and #709 are now on main,
so the three near-identical recursive Drive folder listers can collapse
into one.

New shared helper in shortcuts/drive/list_remote.go:

  driveRemoteEntry { FileToken, Type, RelPath }
  listRemoteFolder(ctx, runtime, folderToken, relBase) -> map[rel]entry

Returns one entry per Drive item (every type), keyed by rel_path.
Subfolders are descended into and the folder's own entry is recorded so
callers can reason about "this rel_path is occupied by a folder"
without re-listing. Pagination via common.PaginationMeta is unchanged.

Each shortcut now derives its own per-shortcut view from the unified
listing:

  - drive_status.go: collapses to remoteFiles (Type=="file" -> token) for
    the content-hash diff.
  - drive_pull.go: derives remoteFiles (Type=="file") for the download
    set, plus remotePaths (every rel_path) as the --delete-local guard.
  - drive_push.go: derives remoteFiles (Type=="file") for upload /
    overwrite / orphan-delete, plus remoteFolders (Type=="folder") for
    the create_folder cache. drivePushRemoteEntry was a duplicate of
    driveRemoteEntry's first two fields and is dropped; the few call
    sites that read .FileToken keep working unchanged.

Per-shortcut copies removed:
  - drive_status.go: listRemoteForStatus, joinRelStatus,
    driveStatusListPageSize/FileType/FolderType
  - drive_pull.go: drivePullListRemote, drivePullJoinRel,
    drivePullListPageSize/FileType/FolderType
  - drive_push.go: drivePushListRemote, drivePushJoinRel,
    drivePushListPageSize/FileType/FolderType, drivePushRemoteEntry

drive_push_test.go's TestDrivePushHelpersRelPath is retargeted at the
shared joinRelDrive; the docstrings on the same-name-conflict tests
were tweaked to refer to "the remoteFiles view" instead of the
just-removed drivePushListRemote.

Net diff: +1 new file, -207 net lines across the four touched files.
All existing unit + e2e dry-run tests pass without behavioral change;
the rel_path / pagination / type-filter contracts each shortcut depends
on are preserved by construction.
wittam-01 pushed a commit that referenced this pull request Apr 30, 2026
* feat(drive): add +pull shortcut to mirror a Drive folder onto local

Adds `drive +pull`, a one-way Drive → local mirror command. It
recursively lists --folder-token, downloads each type=file entry
into --local-dir at the matching relative path, and optionally
deletes local files absent from the remote (mirror semantics).

Implementation notes:

- Listing recurses through subfolders with the standard 200-page
  pagination loop. Online docs (docx, sheet, bitable, mindnote,
  slides) and shortcuts are skipped since there is no equivalent
  local binary to write back. Folder tree is reproduced under
  --local-dir, with parent directories auto-created by FileIO.Save.

- Per-file --if-exists=overwrite (default) | skip controls how
  pre-existing local files are treated; the framework's enum guard
  rejects any other value.

- --delete-local is the only destructive flag and is bound to --yes
  in Validate: --delete-local without --yes is rejected upfront so
  no listing or download even runs. --delete-local --yes performs
  downloads first, then walks --local-dir and removes regular files
  not present in the remote map. This matches the spec doc's
  "high-risk-write" intent for --delete-local without making the
  default pull path require confirmation.

- --local-dir is funneled through validate.SafeLocalFlagPath so
  errors reference --local-dir instead of the framework default
  --file. FileIO().Stat then enforces existence and IsDir.

- Scopes: drive:drive.metadata:readonly + drive:file:download. The
  broader drive:drive is disabled by enterprise policy in some
  tenants.

- Listing helper (drivePullListRemote) is duplicated locally rather
  than reused from drive_status.go because that change is still in
  open PR #692; once it merges, both can be lifted into a shared
  drive package helper. TODO marker is left in the code.

Tests cover six unit scenarios (happy-path with nested subfolder +
docx skipping, --if-exists=skip, --delete-local rejection without
--yes, --delete-local --yes deletes orphans, absolute-path
rejection, bad enum) and four E2E dry-run scenarios (request shape,
absolute path rejection, --delete-local --yes guard, missing
required flag).

* docs(skills): document drive +pull in lark-drive skill

Adds references/lark-drive-pull.md covering parameters, output schema
(summary + per-item action breakdown), the type=file scoping rule,
the --if-exists policy matrix, and the --delete-local + --yes safety
contract. Calls out the network-traffic caveat (pull is full-download,
unlike +status which only fetches when both sides have the file) and
the cwd boundary on --local-dir.

Wires +pull into the Shortcuts table in SKILL.md.

* fix(drive): walk +pull on canonical absolute root to close symlink/.. escape

Same root cause as the +status fix: --local-dir was validated through
SafeLocalFlagPath but the walk used the user-supplied raw string.
SafeLocalFlagPath returns the original value (the canonical form is
discarded), and SafeInputPath itself relies on filepath.Clean for
normalization, which shrinks "link/.." to "." purely as string
manipulation. The kernel then resolves "link/.." through the symlink
target's parent at walk time, putting the traversal outside cwd.

For +pull the bug is more dangerous than for +status because it
travels through --delete-local --yes — a raw walk would let the
delete pass land on files outside cwd.

Fix:
- In Execute, resolve --local-dir via validate.SafeInputPath to get a
  canonical absolute path, and resolve "." the same way for cwd.
- Convert the resolved root back to a cwd-relative form
  (filepath.Rel) for download targets so FileIO.Save's existing
  SafeOutputPath check (which rejects absolute paths) still applies.
- For --delete-local, walk the canonical absolute root, then delete
  via the absolute path. Both values come from the validated
  safeRoot, so kernel path resolution cannot redirect a delete to a
  file outside the canonical subtree.
- drivePullWalkLocal now returns absolute paths instead of rel paths;
  the caller computes the rel_path via filepath.Rel against safeRoot
  for output / remote-set membership checks.

Adds TestDrivePullDeleteLocalDoesNotEscapeViaSymlinkParentRef as a
regression: it stages an "escape" sibling directory containing a
sentinel file, adds a "link" symlink in cwd pointing into it, and
runs +pull --delete-local --yes against an empty remote with
--local-dir "link/..". The sentinel must survive (proving --delete
did not escape) and the in-cwd file must be removed (proving the
walk did run).

* test(drive): pin walker / download behavior on +pull symlink corner cases

Adds three regressions on top of the canonical-root walk fix:

- TestDrivePullSkipsSymlinkInsideRoot: a child symlink inside the
  validated root pointing to a sibling temp dir. Under
  --delete-local --yes with an empty remote, the sentinel inside the
  target must survive (walker did not follow the child symlink) and
  the in-cwd file must be deleted (walker did run).

- TestDrivePullSurvivesCircularSymlinkInsideRoot: a child symlink
  pointing at one of its ancestors. The walk must terminate so the
  test does not hang on the per-test timeout.

- TestDrivePullDownloadDoesNotEscapeViaSymlinkParentRef: pins the
  download half of the fix. With --local-dir "link/.." the canonical
  root resolves to cwd, so the remote file must land in cwd, not
  inside the symlink target's parent. The preexisting sentinel inside
  the escape directory must remain untouched.

* fix(drive): +pull --delete-local must not unlink local files shadowed by online docs

CodeRabbit (PR #696) flagged that the --delete-local pass treated any
local path missing from `remoteFiles` as orphaned, but `remoteFiles` only
records type=file entries. If Drive held a docx/sheet/shortcut at the
same rel_path as a local file, the local file would be unlinked even
though Drive still owned that path.

drivePullListRemote now returns two views:

  - files:    rel_path -> file_token, type=file only (download/skip set)
  - allPaths: every entry's rel_path regardless of type

The download loop continues to consume `files`; the --delete-local pass
consults `allPaths`, so an online-doc shadow of a local filename keeps
the local file safe.

Also routes the local walk and the delete through the vfs abstraction
(vfs.ReadDir + vfs.Remove) instead of filepath.WalkDir + os.Remove.
This drops the //nolint:forbidigo justifications and lines up with how
internal/keychain and internal/registry already do filesystem I/O. The
recursive vfs.ReadDir walker preserves the same "do not follow child
symlinks" semantics that filepath.WalkDir gave us, so the canonical-root
escape protections in 240b772 stay intact.

Adds TestDrivePullDeleteLocalPreservesLocalFileShadowedByOnlineDoc as a
direct regression: Drive serves keep.txt (file) plus notes.docx (docx),
local has both keep.txt and a hand-edited notes.docx; --delete-local
--yes must download keep.txt, leave notes.docx untouched, and report
deleted_local=0.

* fix(drive): count +pull delete failures in summary.failed

CodeRabbit (PR #696) flagged that both delete_failed branches in the
--delete-local pass appended an item but left the `failed` counter at
zero, so the JSON summary could legitimately report `"failed": 0` after
a partially-failed mirror. Increment failed in both branches (the
filepath.Rel error path and the vfs.Remove error path) so summary.failed
reflects every item flagged delete_failed in items[].

Adds TestDrivePullDeleteLocalCountsFailureInSummary, which forces
vfs.Remove to fail by chmod-ing the local dir 0o555 right before the
run and restoring 0o755 in t.Cleanup so t.TempDir teardown still works.

* fix(drive): swap +pull walk/remove back to filepath/os to satisfy depguard

The previous fix-up commits used vfs.ReadDir + vfs.Remove inside the
+pull shortcut, which depguard's "shortcuts-no-vfs" rule rejects:
shortcuts cannot import internal/vfs directly. CI lint failed on the
import line.

Restore the same pattern used in drive_status.go and the prior +pull
walker:

- filepath.WalkDir to enumerate files under the canonical absolute
  root, gated by //nolint:forbidigo with a comment explaining why.
- os.Remove for the actual delete, also gated by //nolint:forbidigo.

The canonical-root safety still holds: validate.SafeInputPath bounds
the walk root inside cwd before WalkDir runs, and WalkDir's default
"do not follow child symlinks" policy is preserved. The two earlier
fixes (drivePullListRemote returning allPaths so online-doc shadows
do not look orphaned, and incrementing failed on delete_failed) stay
in place.

`go test ./shortcuts/drive/...` and `golangci-lint run
--new-from-rev=origin/main` are both clean.

* fix(drive): record remote folder rel_path in +pull allPaths

Follow-up to 45fe4e3. The folder branch in drivePullListRemote merged
descendant rel_paths into allPaths but never recorded the folder's own
rel_path, so a local regular file with the same name as a remote
folder still looked orphaned and got unlinked under --delete-local.

Adds the missing allPaths[rel] for the folder case and a regression:
TestDrivePullDeleteLocalPreservesLocalFileShadowedByRemoteFolder
stages a Drive containing a folder named shadow alongside a
downloadable file, with the local side holding a regular file named
shadow; --delete-local --yes must download keep.txt and leave the
shadow file untouched.

* fix(drive): +pull pagination + dir/file conflict + skill doc symlink claim

Codex review on PR #696 surfaced three issues; addressed in one go:

1. drivePullListRemote only honored next_page_token. The shared
   common.PaginationMeta helper accepts both page_token and
   next_page_token; switched +pull over so a backend reply using
   page_token no longer makes the lister stop at page 1 (which would
   silently drop later remote files from both download and
   --delete-local).

2. --if-exists=skip swallowed mirror conflicts. The skip/overwrite
   branch only checked Stat success, so a local directory shadowing a
   remote regular file was reported as action=skipped. Now Stat's
   IsDir() is checked first; the conflict surfaces as action=failed
   with a message naming the directory, under both --if-exists=skip
   and --if-exists=overwrite, and increments summary.failed.

3. Skill doc told callers to soft-link the target into cwd if they
   wanted to pull from outside cwd. That is wrong: SafeInputPath
   evaluates symlinks before the cwd check, so a symlink pointing
   out-of-tree is rejected. Replaced the bogus shortcut with the
   actually viable options (switch the agent working directory,
   physically move/copy the target, or skip the comparison).

Two new regressions:

- TestDrivePullSurfacesDirectoryFileMirrorConflict — table test over
  both policies asserting failed=1, no skipped, action=failed, plus
  the 'is a directory' hint in the error message.

- TestDrivePullPaginationHandlesPageTokenField — first page returns
  page_token (not next_page_token) with has_more=true; asserts both
  pages are fetched and both files land on disk.

* fix(drive): +pull exits non-zero on item failures; gate --delete-local

Two PR-696 review fixes:

- Item-level failures (download error, dir/file conflict, delete error)
  now surface as a structured partial_failure ExitError instead of a
  success envelope with summary.failed > 0. Exit code becomes non-zero
  and error.detail still carries the {summary, items[]} payload, so
  AI / script callers can detect the failure via the exit code without
  reaching into the JSON body.

- A failed download pass now skips the --delete-local walk entirely.
  Previously +pull would continue removing local-only files even when
  the download phase had partially failed, leaving the mirror in a
  half-synced state (some Drive files missing locally AND some
  local-only files unlinked). Re-runs after fixing the download error
  recover cleanly.

Skill doc / shortcut description / flag desc updated to call the
operation a one-way file-level mirror, since --delete-local only
unlinks regular files and does not prune empty local directories left
behind by remote folder deletes (true directory-level mirroring is
explicitly out of scope).

Tests: existing dir/file-conflict and delete-failure cases now assert
the partial_failure ExitError shape; new test covers the
"download fails => --delete-local skipped" gating contract.

* refactor(drive): consolidate folder-listing helpers into listRemoteFolder

Closes the post-#692 / post-#709 TODO that lived in drive_pull.go (and
the matching note in drive_push.go): both #692 and #709 are now on main,
so the three near-identical recursive Drive folder listers can collapse
into one.

New shared helper in shortcuts/drive/list_remote.go:

  driveRemoteEntry { FileToken, Type, RelPath }
  listRemoteFolder(ctx, runtime, folderToken, relBase) -> map[rel]entry

Returns one entry per Drive item (every type), keyed by rel_path.
Subfolders are descended into and the folder's own entry is recorded so
callers can reason about "this rel_path is occupied by a folder"
without re-listing. Pagination via common.PaginationMeta is unchanged.

Each shortcut now derives its own per-shortcut view from the unified
listing:

  - drive_status.go: collapses to remoteFiles (Type=="file" -> token) for
    the content-hash diff.
  - drive_pull.go: derives remoteFiles (Type=="file") for the download
    set, plus remotePaths (every rel_path) as the --delete-local guard.
  - drive_push.go: derives remoteFiles (Type=="file") for upload /
    overwrite / orphan-delete, plus remoteFolders (Type=="folder") for
    the create_folder cache. drivePushRemoteEntry was a duplicate of
    driveRemoteEntry's first two fields and is dropped; the few call
    sites that read .FileToken keep working unchanged.

Per-shortcut copies removed:
  - drive_status.go: listRemoteForStatus, joinRelStatus,
    driveStatusListPageSize/FileType/FolderType
  - drive_pull.go: drivePullListRemote, drivePullJoinRel,
    drivePullListPageSize/FileType/FolderType
  - drive_push.go: drivePushListRemote, drivePushJoinRel,
    drivePushListPageSize/FileType/FolderType, drivePushRemoteEntry

drive_push_test.go's TestDrivePushHelpersRelPath is retargeted at the
shared joinRelDrive; the docstrings on the same-name-conflict tests
were tweaked to refer to "the remoteFiles view" instead of the
just-removed drivePushListRemote.

Net diff: +1 new file, -207 net lines across the four touched files.
All existing unit + e2e dry-run tests pass without behavioral change;
the rel_path / pagination / type-filter contracts each shortcut depends
on are preserved by construction.
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.

2 participants