Skip to content

feat: unify minute artifacts output to ./minutes/{minute_token}/#604

Merged
Ren1104 merged 8 commits intomainfrom
feat/minutes_artifacts_path_unify
Apr 23, 2026
Merged

feat: unify minute artifacts output to ./minutes/{minute_token}/#604
Ren1104 merged 8 commits intomainfrom
feat/minutes_artifacts_path_unify

Conversation

@Ren1104
Copy link
Copy Markdown
Collaborator

@Ren1104 Ren1104 commented Apr 22, 2026

Summary

Unify the default output layout for minutes +download and vc +notes so that the recording and transcript of the same meeting land under a single ./minutes/{minute_token}/ directory. Zero config, zero env var — works out of the box for Agent pipelines that chain the two commands.

Changes

  • New: shortcuts/common/artifact_path.go — shared DefaultMinuteArtifactDir() helper and artifact_type enum constants.
  • minutes +download:
    • Add --output-dir flag (mutually exclusive with --output).
    • Fix bug where single-token --output pointing at an existing directory reported cannot create parent directory; the path is now promoted to --output-dir (cp semantics).
    • Default layout (no explicit flags) lands to ./minutes/{minute_token}/{server-provided-filename}. Filename resolution (Content-Disposition / Content-Type / {token}.media) is unchanged; only the directory moves.
    • JSON output additionally exposes minute_token + artifact_type: \"recording\" for Agent indexing.
  • vc +notes: When --output-dir is empty, transcript lands to ./minutes/{minute_token}/transcript.txt (unified with the recording path above). Explicit --output-dir ./x preserves the legacy ./x/artifact-{title}-{token}/transcript.txt layout for backwards compatibility.

Test Plan

  • Unit tests: 8 new cases + all existing cases pass (`go test -race ./shortcuts/minutes/... ./shortcuts/vc/... ./shortcuts/common/...`)
  • `golangci-lint v2.1.6 --new-from-rev=origin/main` — 0 issues
  • End-to-end against production Feishu API with a real `minute_token`:
    • 4.1 bug fix: `--output ./existing-dir` → file lands in dir
    • 4.2 aggregation: recording + transcript coexist under `./minutes/{token}/`
    • 4.3 explicit `--output file` / `--output-dir` backwards compatibility preserved
    • 4.4 JSON output contains `minute_token`, `artifact_type`, `saved_path`
    • 4.5 batch mode: each token lands in its own subdir

Related

Internal design doc: VC/Minutes 下载产物统一方案 v1

Summary by CodeRabbit

  • New Features

    • Standardized minute artifact layout (minutes/{minute_token}/) and default transcript filename; download results now include minute_token and artifact_type.
  • Bug Fixes

    • Treat existing --output paths that are directories as output directories; fail fast on unknown filesystem errors.
  • Improvements

    • Clarified --output vs --output-dir semantics, unified default layout, safe-path validation, Content-Disposition filename sanitization, and minute-token validation.
  • Tests

    • Expanded unit and integration tests for downloads, transcripts, and path-safety.

@github-actions github-actions Bot added domain/vc PR touches the vc domain size/L Large or sensitive change across domains or core paths labels Apr 22, 2026
@coderabbitai
Copy link
Copy Markdown

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

Centralizes minute-scoped artifact path constants and helper; introduces --output-dir and redefines --output semantics for downloads; expands per-token result JSON with artifact_type/minute_token; changes VC notes transcript output to the new default minute artifact layout; adds path validation and tests.

Changes

Cohort / File(s) Summary
Artifact path constants
shortcuts/common/artifact_path.go
Adds DefaultMinuteArtifactSubdir, DefaultTranscriptFileName, ArtifactTypeRecording, and DefaultMinuteArtifactDir(minuteToken string) helper.
Minutes download logic & tests
shortcuts/minutes/minutes_download.go, shortcuts/minutes/minutes_download_test.go
Adds --output-dir; reinterprets --output (file vs dir), enforces mutual exclusion, fail-fast on Stat errors, generalizes outputDir handling for single/batch, sanitizes Content-Disposition filenames, includes artifact_type/minute_token in results, and extends tests for traversal, default layout, explicit output-dir, and validation cases.
VC notes transcript layout & tests
shortcuts/vc/vc_notes.go, shortcuts/vc/vc_notes_test.go
When no --output-dir, writes transcripts to DefaultMinuteArtifactDir(minuteToken) with DefaultTranscriptFileName; when --output-dir provided, preserves legacy artifact-{title}-{token} layout but uses standardized filename; adds minute-token format validation and isolated filesystem HTTP tests.
Path validation helper & tests
shortcuts/common/validate.go, shortcuts/common/validate_test.go
Renames/generalizes ValidateSafeOutputDirValidateSafePath to validate arbitrary paths via fio.ResolvePath; tests renamed and expectations preserved for symlink/traversal behaviors.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (user)
  participant Shortcut as ShortcutHandler
  participant MinutesSvc as MinutesService
  participant FS as Filesystem
  participant JSON as ResultEmitter

  CLI->>Shortcut: invoke +download / vc +notes (flags, minuteToken)
  Shortcut->>MinutesSvc: request artifact URL or transcript (minuteToken)
  MinutesSvc-->>Shortcut: return download URL or raw bytes + headers
  Shortcut->>FS: ValidateSafePath / Stat / create dirs if needed
  Shortcut->>FS: write file at resolved path (minutes/{token}/... or explicit)
  Shortcut->>JSON: emit result { minute_token, artifact_type, saved_path | download_url, size_bytes }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

domain/ccm

Suggested reviewers

  • zhaoleibd
  • liangshuo-1

Poem

🐰
I hop through folders, soft and fleet,
Minutes find a tidy seat,
Transcripts tucked in minutes' nest,
Tokens safe — the rabbit's best,
Files snug, secure, and neat. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.03% 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 clearly and concisely summarizes the main objective of unifying minute artifacts output to a single directory structure without being vague or off-topic.
Description check ✅ Passed The description covers all required template sections (Summary, Changes, Test Plan, Related Issues) with substantive content that explains motivation, scope, implementation details, and verification approach.
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/minutes_artifacts_path_unify

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 22, 2026

Codecov Report

❌ Patch coverage is 92.00000% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.37%. Comparing base (04e3a28) to head (e7dfcee).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/vc/vc_notes.go 69.23% 2 Missing and 2 partials ⚠️
shortcuts/common/artifact_path.go 0.00% 2 Missing ⚠️
shortcuts/minutes/minutes_download.go 97.59% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #604      +/-   ##
==========================================
- Coverage   61.05%   60.37%   -0.68%     
==========================================
  Files         400      408       +8     
  Lines       34130    43411    +9281     
==========================================
+ Hits        20838    26210    +5372     
- Misses      11368    15159    +3791     
- Partials     1924     2042     +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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 22, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#feat/minutes_artifacts_path_unify -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: 2

Caution

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

⚠️ Outside diff range comments (1)
shortcuts/vc/vc_notes.go (1)

505-505: ⚠️ Potential issue | 🟡 Minor

Stale --output-dir description after default-layout change.

The help text still says default: current dir, but when --output-dir is omitted the transcript now lands under ./minutes/{minute_token}/transcript.txt (via common.DefaultMinuteArtifactDir). Align the description with the new default so +notes --help doesn't mislead users/Agents.

📝 Suggested wording
-		{Name: "output-dir", Desc: "output directory for artifact files (default: current dir)"},
+		{Name: "output-dir", Desc: "output directory for artifact files. Default when omitted: ./minutes/{minute_token}/ (transcript filename: transcript.txt). When set, legacy layout ./{output-dir}/artifact-{title}-{token}/transcript.txt is used."},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/vc/vc_notes.go` at line 505, Update the help text for the CLI flag
with Name "output-dir" in vc_notes.go so it no longer says "default: current
dir" and instead reflects the new default path used when omitted (the code now
writes transcripts to common.DefaultMinuteArtifactDir, e.g.
"./minutes/{minute_token}/transcript.txt"); locate the flag definition where
{Name: "output-dir", Desc: "..."} is declared and change Desc to mention the new
default layout (or reference common.DefaultMinuteArtifactDir) so the `+notes
--help` output is accurate.
🧹 Nitpick comments (1)
shortcuts/minutes/minutes_download.go (1)

51-65: Consider fail-fast path safety checks for --output/--output-dir in Validate.

Path safety for user-supplied --output/--output-dir is currently only enforced implicitly via runtime.FileIO().Save/Stat at execution time. For consistency with vc +notes (which calls common.ValidateSafeOutputDir in Validate) and to fail fast before contacting the Minutes API, consider adding equivalent checks here.

 	Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
 		tokens := common.SplitCSV(runtime.Str("minute-tokens"))
 		if len(tokens) == 0 {
 			return output.ErrValidation("--minute-tokens is required")
 		}
 		...
 		for _, token := range tokens {
 			if !validMinuteToken.MatchString(token) {
 				return output.ErrValidation("invalid minute token %q: ...", token)
 			}
 		}
+		if outDir := runtime.Str("output-dir"); outDir != "" {
+			if err := common.ValidateSafeOutputDir(runtime.FileIO(), outDir); err != nil {
+				return err
+			}
+		}
 		return nil
 	},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/minutes/minutes_download.go` around lines 51 - 65, The Validate
function for minutes_download.go currently checks minute-tokens but does not
perform early path-safety checks for user-supplied --output/--output-dir; add a
fail-fast check by calling common.ValidateSafeOutputDir (or equivalent) using
runtime.Str("output") and runtime.Str("output-dir") (or the exact flag names
used) inside Validate before contacting the API, returning any validation error;
this mirrors vc +notes behavior and prevents unsafe/invalid paths from
proceeding to execution where runtime.FileIO().Save/Stat would surface them.
🤖 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/minutes/minutes_download.go`:
- Around line 96-100: The new auto-upgrade that rewrites explicitOutputPath into
explicitOutputDir in batch mode weakens the original validation expected by
TestDownload_Validation_OutputWithBatch; restore the intended behavior by adding
an explicit validation check (e.g., in the command's Validate or flag-parsing
logic) that if single == false and explicitOutputPath != "" then return an error
telling the user that --output must be a directory in batch mode (or use
--output-dir), rather than silently converting the flag; reference variables
single, explicitOutputPath and explicitOutputDir and ensure the test
TestDownload_Validation_OutputWithBatch still fails when non-dir --output is
provided in batch mode.
- Around line 81-104: The Stat call on explicitOutputPath currently swallows all
errors; change the logic in the block that inspects explicitOutputPath so that
when calling runtime.FileIO().Stat(explicitOutputPath) you treat a
PathValidationError (or any other non-nil error that is not os.IsNotExist) as a
hard failure and return the error (or wrap it via output.ErrValidation) instead
of ignoring it; only fall through to “treat as file” when Stat returns not found
(os.IsNotExist) or when Stat succeeds and is not a dir. This affects the
explicitOutputPath handling and prevents delayed errors surfaced later in Save.

---

Outside diff comments:
In `@shortcuts/vc/vc_notes.go`:
- Line 505: Update the help text for the CLI flag with Name "output-dir" in
vc_notes.go so it no longer says "default: current dir" and instead reflects the
new default path used when omitted (the code now writes transcripts to
common.DefaultMinuteArtifactDir, e.g.
"./minutes/{minute_token}/transcript.txt"); locate the flag definition where
{Name: "output-dir", Desc: "..."} is declared and change Desc to mention the new
default layout (or reference common.DefaultMinuteArtifactDir) so the `+notes
--help` output is accurate.

---

Nitpick comments:
In `@shortcuts/minutes/minutes_download.go`:
- Around line 51-65: The Validate function for minutes_download.go currently
checks minute-tokens but does not perform early path-safety checks for
user-supplied --output/--output-dir; add a fail-fast check by calling
common.ValidateSafeOutputDir (or equivalent) using runtime.Str("output") and
runtime.Str("output-dir") (or the exact flag names used) inside Validate before
contacting the API, returning any validation error; this mirrors vc +notes
behavior and prevents unsafe/invalid paths from proceeding to execution where
runtime.FileIO().Save/Stat would surface them.
🪄 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: 22c5f986-793e-4cef-aa72-e93793c409fe

📥 Commits

Reviewing files that changed from the base of the PR and between e4d2639 and f06121c.

📒 Files selected for processing (5)
  • shortcuts/common/artifact_path.go
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go
  • shortcuts/vc/vc_notes.go
  • shortcuts/vc/vc_notes_test.go

Comment thread shortcuts/minutes/minutes_download.go Outdated
Comment thread shortcuts/minutes/minutes_download.go Outdated
@Ren1104
Copy link
Copy Markdown
Collaborator Author

Ren1104 commented Apr 22, 2026

@coderabbitai All feedback addressed in 3184006:

Inline review comments (2)

  1. ✅ Stat error swallowing — now explicitly distinguishes fs.ErrNotExist (fall through) vs fileio.PathValidationError / other FS errors (surface immediately).
  2. ✅ Batch-mode --output auto-upgrade — now rejects an existing-file path with explicit "batch mode expects a directory" error. Test updated & renamed to TestDownload_Validation_OutputIsFileInBatchMode.

Outside-diff (1)
3. ✅ vc +notes --output-dir help text — updated to describe the new default ./minutes/{minute_token}/transcript.txt layout and the legacy layout when the flag is set.

Nitpick (1)
4. ✅ Fail-fast path safety — added common.ValidateSafeOutputDir for both --output and --output-dir in minutes_download Validate, mirroring vc +notes.

Verification:

  • Unit tests: all green with -race (go test -race ./shortcuts/minutes/... ./shortcuts/vc/... ./shortcuts/common/...)
  • Lint: golangci-lint v2.1.6 --new-from-rev=origin/main — 0 issues

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Tip

For best results, initiate chat on the files or code changes.

@Ren1104: Thank you for the thorough follow-up! All four items look well-handled:

  • The fs.ErrNotExist vs fileio.PathValidationError distinction is the correct idiomatic approach — surfacing unexpected FS errors early is much safer than swallowing them.
  • Rejecting an existing-file path in batch mode with an explicit error message is a solid UX improvement over the silent auto-upgrade.
  • The common.ValidateSafeOutputDir symmetry between minutes +download and vc +notes keeps the path-safety contract consistent across shortcuts.

The race-clean test run and clean lint check are great signals. 🎉

(´。• ᵕ •。`) ♡


✏️ Learnings added
Learnt from: Ren1104
URL: https://github.com/larksuite/cli/pull/604

Timestamp: 2026-04-22T08:10:12.691Z
Learning: In `larksuite/cli` (`shortcuts/minutes/minutes_download.go`), when checking if a user-supplied `--output` path is an existing directory (to treat it as `--output-dir`), the code explicitly distinguishes `fs.ErrNotExist` (fall through, path does not exist yet) from `fileio.PathValidationError` and other FS errors (surface immediately). Do NOT flag this Stat error handling as swallowing errors.

Learnt from: Ren1104
URL: https://github.com/larksuite/cli/pull/604

Timestamp: 2026-04-22T08:10:12.691Z
Learning: In `larksuite/cli`, `shortcuts/common` (package `common`) provides `ValidateSafeOutputDir` for path-safety validation of output directory flags. Both `minutes +download` (in `shortcuts/minutes/minutes_download.go`) and `vc +notes` (in `shortcuts/vc/vc_notes.go`) call `common.ValidateSafeOutputDir` in their `Validate` step for both `--output` and `--output-dir` flags. Do NOT flag missing explicit path validation for output-dir flags when `common.ValidateSafeOutputDir` is called.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: chanthuang
Repo: larksuite/cli PR: 537
File: skills/lark-mail/references/lark-mail-send.md:0-0
Timestamp: 2026-04-21T03:46:55.148Z
Learning: In `larksuite/cli`, plain-text mode (`--plain-text`) supports large attachments as of commit 4859f7e in PR `#537`. Plain-text emails do not use a download card (HTML); instead, they append a text block with filename, size, and download link. Do not flag `--plain-text` + large attachments as incompatible in future reviews of `shortcuts/mail/large_attachment.go` or related documentation.

Learnt from: evandance
Repo: larksuite/cli PR: 515
File: internal/openclaw/secret_resolve_exec.go:109-123
Timestamp: 2026-04-16T14:18:42.946Z
Learning: In `internal/openclaw/secret_resolve_exec.go` (larksuite/cli, Go), the `maxOutputBytes` check on `stdout.Len()` is intentionally post-hoc (after `cmd.Run()` completes), aligned with OpenClaw's upstream `resolve.ts` which also performs a post-read size check. Both `cmd.Stdout` and `cmd.Stderr` use plain `bytes.Buffer`s. A streaming cap via `io.LimitedReader` with `cmd.Start()` + pipe management is deferred as a future hardening enhancement. Do NOT flag the unbounded buffers or the post-hoc check as a bug in this file.

Learnt from: ViperCai
Repo: larksuite/cli PR: 450
File: shortcuts/slides/slides_media_upload.go:44-49
Timestamp: 2026-04-14T03:13:12.431Z
Learning: In larksuite/cli (Go), `runtime.FileIO().Stat(path)` routes through `LocalFileIO.Stat()` (internal/vfs/localfileio/localfileio.go), which internally calls `SafeInputPath(name)` and wraps failures as `fileio.PathValidationError`. Therefore, any shortcut that validates a user-supplied `--file` path via `runtime.FileIO().Stat()` in its Validate or Execute path already enforces CWD-relative, no-traversal path safety. Do NOT flag missing explicit `validate.SafeInputPath` calls for `--file` flags when `Stat` is called on the same path through this path.

Learnt from: ViperCai
Repo: larksuite/cli PR: 450
File: shortcuts/slides/slides_create.go:50-60
Timestamp: 2026-04-14T03:13:11.481Z
Learning: In `larksuite/cli`, `runtime.FileIO().Stat()` (and `Open`, `Save`, `ResolvePath`) is backed by `LocalFileIO` in `localfileio.go`, which internally calls `SafeInputPath` (or `SafeOutputPath`) before any filesystem access and wraps violations in `fileio.PathValidationError`. Do NOT flag missing explicit `validate.SafeInputPath` calls when code uses `runtime.FileIO().Stat()` / `.Open()` / `.Save()` on user-supplied paths — the FileIO abstraction already enforces CWD-relative path safety. Only require explicit `validate.SafeInputPath` when bypassing the FileIO layer and calling `vfs.*` or `os.*` directly.

Learnt from: evandance
Repo: larksuite/cli PR: 515
File: internal/core/workspace.go:87-92
Timestamp: 2026-04-16T13:25:17.979Z
Learning: In larksuite/cli (`internal/core/workspace.go`), when `vfs.UserHomeDir()` fails (returns an error or an empty string) inside `GetBaseConfigDir()`, the code silently sets `home = ""` and continues with `filepath.Join(home, ".lark-cli")`, resulting in a relative `.lark-cli` path. No `warning:` is printed to stderr because `os.Stderr` is forbidden by the `forbidigo` linter in all `internal/` packages. This silent fallback is intentional — the resulting relative path surfaces as a clear "no such file" error at I/O time, which is considered functionally equivalent. The same silent pattern is used in `keychain_darwin.go:48-50`. Do NOT flag this as a bug, do not suggest adding a stderr warning, and do not suggest changing the function signature to return `(string, error)` or adding a hard-coded fallback path.

Learnt from: yballul-bytedance
Repo: larksuite/cli PR: 345
File: shortcuts/base/workflow_create.go:22-22
Timestamp: 2026-04-09T02:46:18.798Z
Learning: In the `larksuite/cli` repository, for workflow commands (`+workflow-create`, `+workflow-update`), the `--json` flag help text intentionally describes only inline JSON (e.g., `{"title":"My Workflow","steps":[...]}`), but the runtime code (`loadJSONInput` in `shortcuts/base/base_shortcut_helpers.go`) still accepts `path/to/file.json` syntax. This discrepancy between the help text and code behavior is by design: the strict help text guides users toward inline JSON while the code remains backward compatible. Do not flag this as a bug.

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.

Caution

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

⚠️ Outside diff range comments (1)
shortcuts/minutes/minutes_download.go (1)

201-203: ⚠️ Potential issue | 🟡 Minor

Keep --url-only JSON consistent with the new artifact metadata.

Line 202 drops ArtifactType, and the single-token --url-only response on Line 245 still emits only download_url. That means minutes +download --url-only is the one success path that does not include the new minute_token + artifact_type: "recording" fields intended for Agent indexing.

Suggested fix
 			if urlOnly {
-				results[i] = result{MinuteToken: token, DownloadURL: downloadURL}
+				results[i] = result{
+					MinuteToken:  token,
+					ArtifactType: common.ArtifactTypeRecording,
+					DownloadURL:  downloadURL,
+				}
 				continue
 			}
@@
 			if urlOnly {
-				runtime.Out(map[string]interface{}{"download_url": r.DownloadURL}, nil)
+				runtime.Out(map[string]interface{}{
+					"minute_token":  r.MinuteToken,
+					"artifact_type": r.ArtifactType,
+					"download_url":  r.DownloadURL,
+				}, nil)
 			} else {

Also applies to: 244-252

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

In `@shortcuts/minutes/minutes_download.go` around lines 201 - 203, When urlOnly
is true the code only sets MinuteToken and DownloadURL but omits ArtifactType,
and the single-token (--url-only) response also emits only download_url; update
the urlOnly branch that writes into the results slice (the result struct) to
also set ArtifactType = "recording" (or the appropriate constant) so the JSON
includes artifact_type, and update the single-token response path that returns
only download_url to include minute_token and artifact_type:"recording" as well
so both the multi-result (results) and single-token response paths emit
minute_token, download_url, and artifact_type for Agent indexing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@shortcuts/minutes/minutes_download.go`:
- Around line 201-203: When urlOnly is true the code only sets MinuteToken and
DownloadURL but omits ArtifactType, and the single-token (--url-only) response
also emits only download_url; update the urlOnly branch that writes into the
results slice (the result struct) to also set ArtifactType = "recording" (or the
appropriate constant) so the JSON includes artifact_type, and update the
single-token response path that returns only download_url to include
minute_token and artifact_type:"recording" as well so both the multi-result
(results) and single-token response paths emit minute_token, download_url, and
artifact_type for Agent indexing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd19c4d2-8134-400b-92c5-1e24c6606db7

📥 Commits

Reviewing files that changed from the base of the PR and between f06121c and 3184006.

📒 Files selected for processing (3)
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go
  • shortcuts/vc/vc_notes.go
✅ Files skipped from review due to trivial changes (1)
  • shortcuts/minutes/minutes_download_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/vc/vc_notes.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.

🧹 Nitpick comments (1)
shortcuts/vc/vc_notes.go (1)

339-347: Minutetoken validation: inconsistency with minutes +download, but path safety is already enforced by FileIO layer.

The concern about minuteToken escaping the minutes/ tree is mitigated: runtime.FileIO().Save() internally calls SafeOutputPath(), which rejects any path traversal attempts via canonicalization and CWD-boundary validation. However, vc +notes inconsistently lacks the upfront token validation that minutes +download applies (regex requiring lowercase alphanumeric only). Consider validating tokens in the Validate step to match minutes +download for better fail-fast UX and consistency, rather than relying on downstream FileIO protection.

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

In `@shortcuts/vc/vc_notes.go` around lines 339 - 347, Add a fail-fast validation
for minuteToken in the vc +notes command's Validate step (before building
dirName/transcriptPath) to mirror the minutes +download behavior: check the
minuteToken value matches the same lowercase alphanumeric regex used by minutes
+download (reject anything with non-lowercase-alnum characters) and return a
validation error if it fails. This should be done alongside existing uses of
minuteToken/sanitizeDirName and not rely solely on runtime.FileIO().Save()’s
SafeOutputPath; update the Validate logic that runs prior to constructing
dirName/transcriptPath to enforce the token rule for consistency and better UX.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shortcuts/vc/vc_notes.go`:
- Around line 339-347: Add a fail-fast validation for minuteToken in the vc
+notes command's Validate step (before building dirName/transcriptPath) to
mirror the minutes +download behavior: check the minuteToken value matches the
same lowercase alphanumeric regex used by minutes +download (reject anything
with non-lowercase-alnum characters) and return a validation error if it fails.
This should be done alongside existing uses of minuteToken/sanitizeDirName and
not rely solely on runtime.FileIO().Save()’s SafeOutputPath; update the Validate
logic that runs prior to constructing dirName/transcriptPath to enforce the
token rule for consistency and better UX.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c478858e-f99a-4917-9b6b-731134cc8ea7

📥 Commits

Reviewing files that changed from the base of the PR and between 3184006 and eb908ec.

📒 Files selected for processing (5)
  • shortcuts/common/artifact_path.go
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go
  • shortcuts/vc/vc_notes.go
  • shortcuts/vc/vc_notes_test.go
✅ Files skipped from review due to trivial changes (3)
  • shortcuts/common/artifact_path.go
  • shortcuts/minutes/minutes_download_test.go
  • shortcuts/minutes/minutes_download.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 the current code and only fix it if needed.

Inline comments:
In `@shortcuts/minutes/minutes_download.go`:
- Around line 206-218: The server-provided filenames must be constrained to the
per-token artifact directory: in the download flow that builds downloadOpts (see
downloadOpts struct usage and code paths setting opts.outputDir =
common.DefaultMinuteArtifactDir(token) and opts.outputPath =
explicitOutputPath), sanitize and validate any filename extracted from
Content-Disposition before joining it to opts.outputDir; specifically, replace
the filename with filepath.Base(filename) (or reject if it contains path
separators or traversal components like ".."), then join via
filepath.Join(opts.outputDir, sanitizedName) and verify the resulting path is
inside the intended directory (e.g., via filepath.Clean + filepath.Rel or an
equivalent containment check) before passing to FileIO.Save; if validation
fails, return an error instead of writing outside the per-token directory.
🪄 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: 31a505a2-b2c0-4150-acea-2fb56e973967

📥 Commits

Reviewing files that changed from the base of the PR and between eb908ec and 31d5feb.

📒 Files selected for processing (6)
  • shortcuts/common/artifact_path.go
  • shortcuts/common/validate.go
  • shortcuts/common/validate_test.go
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go
  • shortcuts/vc/vc_notes.go
✅ Files skipped from review due to trivial changes (1)
  • shortcuts/common/artifact_path.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/minutes/minutes_download_test.go

Comment thread shortcuts/minutes/minutes_download.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.

🧹 Nitpick comments (1)
shortcuts/minutes/minutes_download.go (1)

133-140: Result schema and per-token JSON envelope changes look consistent.

artifact_type/minute_token/saved_path/size_bytes are set only on the success path (line 226–231); early-error paths only populate MinuteToken+Error, and omitempty keeps the JSON clean. The single branch emits download_url for url-only and the artifact triple otherwise — matches the PR-documented Agent-indexing contract.

Minor nit (non-blocking): size_bytes uses omitempty, so a legitimate 0-byte download would silently omit the field. Unlikely in practice for media, but if the Agent parses this strictly, you may want to drop omitempty on SizeBytes for the single-success envelope. Happy to skip if intentional.

Also applies to: 226-252

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

In `@shortcuts/minutes/minutes_download.go` around lines 133 - 140, The result
struct's SizeBytes field currently has `omitempty` which will drop a legitimate
0 value from JSON; update the result struct (type result) so that SizeBytes is
always emitted for successful single-download envelopes — remove `omitempty`
from SizeBytes (or otherwise ensure the success-path JSON builder explicitly
includes size_bytes=0) so agents parsing the response can rely on the field
being present for success cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shortcuts/minutes/minutes_download.go`:
- Around line 133-140: The result struct's SizeBytes field currently has
`omitempty` which will drop a legitimate 0 value from JSON; update the result
struct (type result) so that SizeBytes is always emitted for successful
single-download envelopes — remove `omitempty` from SizeBytes (or otherwise
ensure the success-path JSON builder explicitly includes size_bytes=0) so agents
parsing the response can rely on the field being present for success cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 90eb1fba-0662-4ed4-b517-4a47b8d8250c

📥 Commits

Reviewing files that changed from the base of the PR and between 31d5feb and aecf67d.

📒 Files selected for processing (2)
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go
✅ Files skipped from review due to trivial changes (1)
  • shortcuts/minutes/minutes_download_test.go

@Ren1104 Ren1104 requested a review from zhaoleibd April 22, 2026 09:30
Comment thread skills/lark-minutes/references/lark-minutes-download.md Outdated
Comment thread skills/lark-minutes/references/lark-minutes-download.md Outdated
@Ren1104 Ren1104 force-pushed the feat/minutes_artifacts_path_unify branch from b7a2ff8 to 89593ed Compare April 23, 2026 07:56
@Ren1104 Ren1104 force-pushed the feat/minutes_artifacts_path_unify branch from 89593ed to e7dfcee Compare April 23, 2026 08:03
@Ren1104 Ren1104 merged commit c7ced37 into main Apr 23, 2026
21 checks passed
@Ren1104 Ren1104 deleted the feat/minutes_artifacts_path_unify branch April 23, 2026 08:37
@liangshuo-1 liangshuo-1 mentioned this pull request Apr 23, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/vc PR touches the vc 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