* feat: (MacOS) add fallback file-based master key storage
* refactor(keychain): improve master key file handling and corruption checks
- Replace temporary file approach with direct file creation
- Add explicit corruption checks for existing keys
- Ensure atomic operations and proper cleanup on failure
* docs(keychain): add comments to clarify constants and variables
Add descriptive comments to explain the purpose of timeout, crypto parameters, and test variables in the macOS keychain implementation.
* fix(keychain): use atomic write for master key initialization
* fix(keychain): add retry logic for reading master key file
Add retry mechanism when reading existing master key file to handle potential race conditions. Return early if read error occurs instead of waiting for all retries.
* refactor(keychain): simplify master key validation logic
Restructure the key validation flow to reduce redundant checks and improve readability. The corrupted key check is moved after the error handling block for better logical flow.
* refactor(keychain): replace os package with vfs for file operations
Use vfs package instead of os for file operations to improve testability and
abstract filesystem access. This change makes it easier to mock filesystem
operations in tests and provides a consistent interface for file handling.
* feat: add transport extension with interceptor pre/post hooks
Add extension/transport package following the same Provider pattern as
credential and fileio extensions. The Interceptor interface uses a
PreRoundTrip/post-closure design that guarantees built-in transport
decorators (SecurityHeader, SecurityPolicy, Retry) cannot be skipped,
overridden, or tampered with by extensions. The original request context
is restored after PreRoundTrip to prevent context tampering.
Change-Id: I2e51ff67a0e2d8d32944a0565c2a6781110f281f
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reset registry test globals more completely, tighten the overlay pollution regressions, and ensure tenant scope coverage tests rebuild a fresh isolated registry before asserting.
* fix(issue-labels): reduce mislabeling and handle missing labels
Make type classification more conservative to avoid incorrect labels, and avoid skipping entire issues when some managed labels are missing.
* test(issue-labels): add more real-world issue samples
Add labeled/unlabeled issue examples to cover question/bug/enhancement and domain inference.
* test(issue-labels): avoid duplicate issue samples
Keep one sample per source_url to reduce confusion and maintain stable regression coverage.
* fix(issue-labels): include missing-label-only items in JSON output
Keep stderr and JSON output consistent under --only-missing when desired labels are missing from the repo.
* feat: add strict mode identity filter, profile management and credential extension
Port changes from feat/strict-mode-identity-filter_3 branch:
- Add strict mode for identity filtering and configuration
- Add profile management commands (add/list/remove/rename/use)
- Add credential extension framework (registry, env provider)
- Add VFS abstraction layer
- Refactor factory default and client options
- Update shortcuts to use new credential and validation patterns
Change-Id: I8c104c6b147e1901d94aefcefe35a174932c742b
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: go mod tidy
Change-Id: I0f610ccea6bc874248e84c24770944a3071dcc57
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fix test failures from credential provider migration
- Remove unused TAT stub registrations in api and service tests
(CredentialProvider manages tokens, SDK no longer calls TAT endpoint)
- Update strict mode integration test: +chat-create now supports user
identity, so it should succeed under strict mode user
Change-Id: Iab51c2e12a97995e0b95dcd71df212d2d1f76570
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: migrate remaining os calls to internal/vfs
Replace direct os.Stat/Open/MkdirAll/OpenFile/Remove/ReadDir/UserHomeDir
with vfs equivalents in shortcuts/minutes, shortcuts/drive, and
internal/keychain. Add ReadDir to the vfs interface and OsFs implementation.
Change-Id: I8f97e5fb3e1731b4684d276644fcb10fae823067
* fix: resolve gofmt and goimports formatting issues
Change-Id: If61578631f5698f7ca2d9a946ca59753651463fb
* feat: add Flag.Input support for @file and stdin input sources
Add framework-level support for reading flag values from files (@path)
or stdin (-), solving the fundamental problem of passing complex text
(markdown, multi-line content) via CLI arguments where shell escaping
breaks content. Closes#239, fixes#163.
- Add File/Stdin constants and Input field to Flag struct
- Add resolveInputFlags() in runner pipeline (pre-Validate)
- Support @@ escape for literal @ prefix
- Guard against multiple stdin consumers
- Auto-append "(supports @file, - for stdin)" to help text
- Apply to: docs +create/+update --markdown, im +messages-send/+reply
--text/--markdown/--content, task +comment --content,
drive +add-comment --content
Change-Id: I305a326d972417542aeadd70f37b74ea456461ef
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fix pre-existing test failures in task, minutes, and registry
- task/minutes: remove unused tenant_access_token httpmock stubs
(TestFactory's testDefaultToken provides tokens directly, so the
HTTP stub was never consumed and failed verification)
- registry: fix hasEmbeddedData() to check for actual services instead
of just byte length (meta_data_default.json has empty services array)
Change-Id: Ic7b5fc7f9de09137a7254fe1ddf47d24ade40587
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: suppress nilerr lint for intentional nil returns
Both cases intentionally return nil on error for graceful degradation:
- profile list: show friendly message when config is not initialized
- service: skip scope check when token resolution fails
Change-Id: I7285c37277c9b0361a421ab00359244c2cd150b3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- runner.go: fail fast when Input is used on non-string flags
- remote_test.go: rename hasEmbeddedData → hasEmbeddedServices
- profile/list.go: add omitempty to optional JSON fields
- service.go: surface context cancellation errors in scope check
Change-Id: I7072d41f8c711b4b37c542e32dfd8150f42b13c0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: tighten credential resolution and profile flows
Change-Id: I83f6d424540eab9b1708944b9b6e26e8477cc60d
* refactor: centralize identity hint resolution
Change-Id: I38d5f98160b92adb62dc929ae73697ae5b3d64f8
* fix: surface unverified extension identities
Change-Id: Ia86d9bd19add9010176339ec4cc89deb033f5b4f
* fix: honor runtime credential sources in config views
Change-Id: I40b2ffedc5c1db5e08e86b9472ea2b84fa02bb29
* fix: prefer runtime values in config show commands
Change-Id: I5663a53e147577f0f1f533f67d12bea504e6b839
* Revert "fix: prefer runtime values in config show commands"
This reverts commit 4f9db3a227.
* Revert "fix: honor runtime credential sources in config views"
This reverts commit b3bfd526c5.
* fix: harden profile flows and credential boundaries
Change-Id: Ica61cd2730a639f71516cb1b237a639cb6511f7a
* fix: optimize profile and config inspection for agents
Change-Id: I19c368102f19654952638180ab947788a6971563
* refactor: unify credential env contracts
Change-Id: I0ff2c0a650ea53589a0626333e8f6e628ef10a54
* docs: expand AGENTS guidance
Change-Id: I289027dfd364c92205012feef6f05037066c035b
* fix: resolve regression bugs found during PR #252 review
- im: fix double SafeInputPath in resolveLocalMedia → uploadImageToIM/
uploadFileToIM chain that rejected all local image/file uploads
- credential: stop writing plain-text warnings to stderr, preserving
JSON envelope contract for AI agent consumers
- profile add: reject duplicate app-id to prevent keychain credential
collisions across profiles
- profile rename: exclude self when checking name uniqueness so renaming
to own appId works correctly
- config: replace bare fmt.Errorf with output.Errorf in save-failure
paths (default_as, strict_mode ×2, profile add)
- factory: remove unused resolveDefaultAs method (lint)
Change-Id: I6aa0d064414016f367f1edb08dd0604adf7bf13d
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove flaky TestColdStart_UsesEmbedded (race in registry)
The test triggers a data race: resetInit() writes package globals while
a background goroutine from a previous test may still be reading them.
The embedded-data path is covered by other tests.
Change-Id: I7a0c3bf85a9fb337b9279c9053697f40a0c0a0d4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: type-strengthen Brand and DefaultAs across credential chain
Replace raw string fields with typed enums for compile-time safety:
- extension/credential: add Brand and Identity named types
- internal/core: AppConfig.DefaultAs and CliConfig.DefaultAs → Identity
- internal/credential: Account.DefaultAs and IdentityHint.DefaultAs → core.Identity
The full data flow is now typed end-to-end:
extcred.Brand → core.LarkBrand (named-type cast)
extcred.Identity → core.Identity (named-type cast)
No string intermediaries, no implicit conversions.
Change-Id: I715b3b3f033fcb624010f1af9619e3562740ef08
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: fix gofmt alignment in extension/credential/types.go
Change-Id: Ibfac0703a5a28f3c6ba4a47bf40696028d0f3b90
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove file/stdin input support from task comment content flag
Change-Id: If49704ca4612465a23bd30b755d6e72a35fc2349
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(cmdutil): remove dead code autoDetectIdentity
autoDetectIdentity() is only called from tests, never from production
code. Remove it along with its 3 test cases to reduce surface area
before the upcoming ctx propagation refactor.
Change-Id: I35a188860f17656f3e1fe9874f87f284985ae196
* refactor(cmdutil): add ctx parameter to resolveIdentityHint
Private method resolveIdentityHint now accepts context.Context and
passes it to CredentialProvider.ResolveIdentityHint instead of using
context.Background(). The caller (ResolveAs) still uses
context.Background() temporarily until its own signature is updated.
Change-Id: I14634a4e0dc1d657d56936ba61a7b7a206da8ac4
* refactor(cmdutil): add ctx parameter to ResolveStrictMode
ResolveStrictMode now accepts context.Context and passes it to
CredentialProvider.ResolveAccount instead of using context.Background().
Callers in cobra RunE pass cmd.Context(); callers outside RunE
(cmd/root.go startup, tests) use context.Background() explicitly.
Change-Id: I31be48e548ac5ac5640a65f3bfdde4a53ed1dc7e
* refactor(cmdutil): add ctx parameter to CheckStrictMode
CheckStrictMode now accepts context.Context and forwards it to
ResolveStrictMode. Callers pass cmd.Context() (cobra RunE) or
opts.Ctx (APIOptions/ServiceMethodOptions).
Change-Id: I47888519d4cae8c94054771c32aff075565a8cdc
* refactor(cmdutil): add ctx parameter to ResolveAs
ResolveAs now accepts context.Context as first parameter and forwards
it to ResolveStrictMode and resolveIdentityHint. This completes the
ctx propagation chain: all Factory methods that call
CredentialProvider now receive ctx from cobra cmd.Context().
No more context.Background() calls remain in factory.go for
credential provider operations.
Change-Id: I6d10b6350e3b149470660de3e7855614314e8b29
* test: fix gofmt in cmdutil factory tests
Change-Id: I4a87d5a815b959f14cc4371b73dee4aae106932f
* fix: remove file/stdin input support from im send/reply and drive comment
The Input (file/stdin) feature is not yet ready for these flags:
- im send/reply: --content, --text, --markdown
- drive add-comment: --content
Retained only in doc create/update where markdown from file is essential.
Change-Id: I582b6349528fccb639ad9edc84650cca3b68535c
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: liushiyao <liushiyao.1206@bytedance.com>
* fix(mail): restore CID validation and stale PartID lookup lost in revert (#199)
The revert of PR #81 (eda2b9c) also removed two independent bugfixes:
1. CID character validation in newInlinePart — reject spaces, tabs,
angle brackets, and parentheses to prevent malformed MIME output.
2. Stale PartID lookup in validateInlineCIDAfterApply and
validateOrphanedInlineCIDAfterApply — use findPrimaryBodyPart by
media type instead of findPart by PrimaryHTMLPartID, which can go
stale when ops restructure the MIME tree.
* test(mail): add tests for CID character validation and stale PartID lookup
- TestAddInlineRejectsInvalidCharactersInCID: verify spaces, tabs,
embedded angle brackets, and parentheses in CID are rejected.
- TestValidateInlineCIDAfterSetBody: verify inline CID validation
works correctly after set_body restructures the MIME tree (covers
the findPrimaryBodyPart fix for stale PartID).
* fix(mail): add CID character validation to replaceInline and strengthen test assertions
Address CR feedback:
1. Add the same CID character validation (spaces, tabs, angle brackets,
parentheses) to replaceInline, matching the check in newInlinePart.
Previously replace_inline could bypass the restriction.
2. Strengthen orphaned CID test assertion to check for specific
"orphaned cids" error message, not just non-nil error.
3. Add TestReplaceInlineRejectsInvalidCharactersInCID to cover the
new validation in replace_inline.
* ci: add issue labeler workflow
Add a manual GitHub Actions workflow and script to poll issues and apply type/domain labels.
* feat(issue-labels): refine heuristics and add docs
Improve domain detection and add safeguards to avoid overriding manual type triage by default. Refresh regression samples from real issues and document usage.
* ci(issue-labels): enable hourly scheduled labeling
Run hourly on schedule with write mode by default while keeping manual dispatch dry-run by default.
* ci(issue-labels): shorten lookback window to 6h
Reduce scheduled scan window while keeping overlap for missed runs.
* ci(issue-labels): opt into Node 24 actions runtime
Set FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 and use Node 24 for the script runtime to avoid upcoming Node 20 deprecation warnings.
* ci(issue-labels): restore lookback input for manual runs
Allow workflow_dispatch to override lookback_hours while keeping hourly schedule fixed.
* ci(issue-labels): upgrade checkout/setup-node to v6
Use actions/checkout@v6 and actions/setup-node@v6 to align with Node 24 runtime and avoid Node 20 deprecation warnings.
* fix(ci): label only unlabeled issues via search api
* fix(ci): refine issue labeling heuristics from live issues
* fix(ci): address remaining issue label review comments
* fix(ci): fix issue label arg parsing regression
* docs(issue-labels): clarify one-shot unlabeled triage scope
* feat(drive): support multipart upload for files larger than 20MB
Previously, `drive +upload` rejected files exceeding 20MB with a
validation error. Now files > 20MB automatically use the three-step
chunked upload API (upload_prepare → upload_part × N → upload_finish),
removing the size ceiling for Drive uploads.
Tested with a 189MB file (48 blocks × 4MB) against a live Feishu tenant.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(drive): add upload error-path tests to improve coverage
Cover small-file upload (upload_all) success + error paths and
multipart upload error paths (invalid prepare, part API error,
part invalid JSON, finish missing token, custom name flag).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: cli e2e test framework and demo
* feat: add cli-e2e-testcase-writer skill and task case
* feat: add cli e2e config and fix test resource prefix
All HTTP clients previously used http.DefaultTransport which silently respects
HTTP_PROXY/HTTPS_PROXY env vars, allowing credentials to transit through
untrusted proxies. This adds a proxy detection warning and an opt-out switch
(LARK_CLI_NO_PROXY=1) so security-sensitive users can disable proxy entirely.
- Redact proxy credentials in warning output (handles both scheme-prefixed and bare URL formats)
- Suppress warning when LARK_CLI_NO_PROXY is already set
- Use FallbackTransport singleton for nil-Base fallback paths to preserve connection pooling
- Emit proxy warning on both HTTP client and Lark SDK client paths
Change-Id: Ibed7d0470409c73fbd42bccac6673f9fc5e87a83
- Add --as user support to +chat-create
- Add UserScopes (im:chat:create_by_user) / BotScopes (im:chat:create)
- Update skill docs and reference files to reflect user/bot support
- Default identity remains bot (first element of AuthTypes)
Change-Id: I6be0a160567a0d87a92f176ae12297a11d06dcb1
* feat(auth): add response logging and centralize path constants
* refactor(auth): improve response logging and error handling
* fix(auth): ensure log cleanup runs only once per process
Add flag to track if cleanup has run and prevent duplicate executions
Add test to verify cleanup only runs once
* refactor(auth): simplify log writer and cleanup logic
* docs(auth): add comments to auth paths and logging functions
* style(auth): fix indentation in path constants
* docs(auth): add missing function comments across auth package
* docs(tests): add descriptive comments to auth test functions
* test(auth): rename test case and cleanup unused params
* fix(auth): handle file close error in auth response logging
* fix(auth): ensure log cleanup runs only once
* refactor(auth): replace custom log writer with standard logger
* feat(auth): add structured logging for keychain errors
* fix(auth): remove goroutine from auth log cleanup to prevent race condition
* fix(auth): remove goroutine from auth log cleanup to prevent race condition
* refactor(auth): move auth logging logic to keychain package
* docs(mail): add identity guidance to prefer user over bot for mail APIs
Add an identity selection section to the mail skill documentation,
guiding AI agents to default to --as user when operating on mailboxes.
Bot identity requires the app to have tenant-level mail scopes enabled
in the developer console, which most apps do not.
* docs(mail): clarify identity selection wording and bot scope limits
- Replace ambiguous "默认使用" with "策略上应优先显式使用" to
distinguish policy recommendation from CLI default (auto)
- Note that bot identity only supports read operations; all write
operations (send, reply, forward, draft edit) require user identity
- Rewrite decision rules by read/write classification
Users reported that AI agents sometimes wrote shell scripts to manually
extract and re-decode JSON string fields (e.g. unicode_escape), causing
Chinese character corruption. Add notes to mail skill docs clarifying
that JSON output can be read directly without additional encoding
conversion.
Mail scope tests (TestConfirmSendMissingScope*) were calling
auth.SetStoredToken/RemoveStoredToken which accessed the real macOS
keychain via go-keyring, causing persistent popup dialogs when the
master key was missing. Add keyring.MockInit() to swap in an in-memory
backend during tests.
Node.js https.get() does not honor https_proxy/HTTP_PROXY env vars,
causing silent download failures behind firewalls. Switch to curl which
natively supports proxy settings, and add npmmirror.com as a fallback
mirror for regions where GitHub is slow or blocked.
Change-Id: If9ace1e467e46f2a3009610a808bce8d78259e78
* feat: add --jq flag for filtering JSON output across all command types
Add jq expression filtering (--jq / -q) to api, service, and shortcut
commands using gojq. Includes early expression validation, mutual
exclusion checks with --output and non-json --format, pagination+jq
aggregation path, and comprehensive test coverage.
* fix: correct gofmt alignment in jq_test.go struct literal
* fix: downgrade gojq to v0.12.17 to keep Go 1.23 compatibility
gojq v0.12.18 requires Go 1.24, which unnecessarily bumped the project
minimum version. v0.12.17 requires only Go 1.21 and provides the same
jq functionality needed.
* refactor: consolidate jq validation and pagination logic
Extract ValidateJqFlags() and PaginateWithJq() shared functions to
eliminate duplicated jq logic across api, service, and shortcut commands.
* fix: reject --jq for non-JSON responses and propagate shortcut jq errors
- HandleResponse now returns a validation error when --jq is used with
a non-JSON Content-Type instead of silently falling through to binary save.
- Shortcut runtime jq errors are captured in RuntimeContext.outputErr
and propagated as the command exit code, matching api/service behavior.
Accept escaped and full-width sheet/range separators in sheets shortcuts.
Normalize range parsing in the shared sheets helper so read, find, write,
and append handle \!, \!, and ! consistently.
Add regression tests for separator normalization in dry-run paths.
- Add --as user support to +messages-send and +messages-reply
- Add UserScopes (im:message.send_as_user) / BotScopes (im:message:send_as_bot)
- Add DoAPIAsBot to RuntimeContext so file/image uploads always use bot
identity even when the surrounding command runs as user
- Update skill docs and reference files to reflect user/bot support
- Default identity remains bot (first element of AuthTypes)
* fix(mail): on-demand scope checks, event filtering, and watch lifecycle
- Remove mail:user_mailbox.folder:read from watch's static Scopes; add
validateFolderReadScope and validateLabelReadScope that check
permissions on-demand when listMailboxFolders/listMailboxLabels is
called (same pattern as validateConfirmSendScope).
- Resolve --mailbox me to real email address via profile API for event
filtering, preventing other users' mail events from being processed.
Block startup if resolution fails, with proper error type distinction.
- Add unsubscribe cleanup (guarded by sync.Once) on all exit paths:
SIGINT/SIGTERM, profile resolution failure, and WebSocket failure.
- Remove bot from AuthTypes since bot tokens cannot subscribe.
- Include profile lookup in dry-run output and update tests.
- Update fetchMailboxPrimaryEmail to return error for diagnostics.
- Update documentation for on-demand scope requirements.
* fix(mail): preserve original error in enhanceProfileError fallback
Return the original error directly for non-permission failures instead
of wrapping with fmt.Errorf, so structured exit codes (ExitNetwork,
ExitAPI) are preserved for scripting.
* Revert "fix(mail): clarify that file path flags only accept relative paths (#141)"
This reverts commit 1ffe870dc8.
* Revert "feat(mail): auto-resolve local image paths in draft body HTML (#81) (#139)"
This reverts commit 70c72a2c02.
* Reapply "fix(mail): clarify that file path flags only accept relative paths (#141)"
This reverts commit d465e085b1.
* feat: add TestGenerateShortcutsJSON for registry shortcut export
Add a test that exports all shortcuts as JSON when SHORTCUTS_OUTPUT
env var is set, enabling the registry repo to extract shortcut
metadata without depending on a dump-shortcuts CLI command.
* refactor(keychain): improve error handling and consistency across platforms
- Change platformGet to return error instead of empty string
- Add proper error wrapping for keychain operations
- Make master key creation conditional in getMasterKey
- Improve error messages and handling for keychain access
- Update dependent code to handle new error returns
* docs(keychain): improve function documentation and error message
Add detailed doc comments for all platform-specific keychain functions to clarify their purpose and behavior. Also enhance the error hint message to include a suggestion for reconfiguring the CLI when keychain access fails.
* refactor(keychain): reorder operations in platformGet for better error handling
Check for file existence before attempting to read and get master key
* fix(keychain): improve error handling and consistency across platforms.
* fix(keychain): handle corrupted master key case
* fix(keychain): handle I/O errors when reading master key
* feat(ci): add PR size label pipeline
* chore(ci): make PR label sync non-blocking
* feat(ci): add dry-run mode for PR label sync
* feat(ci): add PR label dry-run samples
* test(ci): update PR label samples with real historical merged PRs
Replaced synthetic or open PR samples with actual merged/closed PRs from the
repository to provide a more accurate reflection of the size label categorization.
Added 4 samples each for sizes S, M, and L covering docs, fixes, ci, and features.
* feat(ci): add high-level area tags for PRs
Based on user feedback, fine-grained domain labels (like `domain/base`) are too detailed for the early stages.
This change adds support for applying `area/*` tags to indicate which important top-level modules a PR touches.
Currently tracked areas:
- `area/shortcuts`
- `area/skills`
- `area/cmd`
Minor modules like docs, ci, and tests are intentionally excluded to keep tags focused on critical architectural components.
* refactor(ci): extract pr-label-sync logic to a dedicated directory
To avoid polluting the root `scripts/` directory, moved `sync_pr_labels.js` and
`sync_pr_labels.samples.json` into a new `scripts/sync-pr-labels/` folder.
Added a dedicated README to document its usage and behavior.
Updated `.github/workflows/pr-labels.yml` to reflect the new path.
* refactor(ci): rename pr label script directory for simplicity
Renamed `scripts/sync-pr-labels/` to `scripts/pr-labels/` to keep directory
names concise. Updated internal references and GitHub workflow files to point
to the new path.
* ci: add GitHub Actions workflow to check skill format
* test(ci): update sample json to include expected_areas
Added `expected_areas` lists to each sample in `samples.json` to reflect
the newly added `area/*` high-level module tagging logic. Allows testing
to accurately check both `size/*` and `area/*` outputs.
* refactor(scripts): move skill format check to isolated directory and add README
* test(scripts): add positive and negative tests for skill format check
* fix(scripts): revert skill changes and downgrade version/metadata checks to warnings
* fix(scripts): completely remove version check and skip lark-shared
* refactor(ci): improve pr-labels script readability and maintainability
- Reorganized code into logical sections with clear comments
- Encapsulated GitHub API interactions into a reusable `GitHubClient` class
- Extracted and centralized classification logic into a pure `evaluateRules` function
- Replaced magic numbers with named constants (`THRESHOLD_L`, `THRESHOLD_XL`)
- Fixed `ROOT` path resolution logic
- Simplified conditional statements and control flow
* ci: fix setup-node version in pr-labels workflow
* tmp
* refactor(ci): replace generic area labels with business-specific ones
- Add PATH_TO_AREA_MAP to map shortcuts/skills paths to business areas (im, vc, ccm, base, mail, calendar, task, contact)
- Replace importantAreas with businessAreas throughout the codebase
- Remove area/shortcuts, area/skills, area/cmd generic labels
- Now generates specific labels like area/im, area/vc, area/ccm, etc.
- Update samples.json expected_areas to match new behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): address PR review feedback for label scripts and workflows
- Add `edited` event to PR labels workflow to trigger on title changes
- Add security warning comment in pr-labels.yml workflow
- Update pr-labels README with latest business area labels
- Exclude `skills/lark-*` paths from low risk doc classification
- Handle renamed files properly in PR path classification
- Fix YAML frontmatter extraction to handle CRLF line endings
- Use precise regex for YAML key validation instead of substring match
- Fix exit code checking logic in skill-format-check test script
- Translate Chinese comments in skill-format-check to English
* fix(skill-format-check): address CodeRabbit review feedback
- Fix frontmatter closing delimiter detection to strictly match '---' using regex, preventing invalid closing tags like '----' from passing.
- Improve test fixture reliability by failing tests immediately if fixture preparation fails, avoiding false positives.
* fix: address review comments from PR 148
- ci: warn when PR label sync fails in job summary
- test(skill-format-check): capture validator output for negative tests
- fix(skill-format-check): catch errors when reading SKILL.md to avoid hard crashes
* fix: add error handling for directory enumeration in skill-format-check
- refactor: use `fs.readdirSync` with `{ withFileTypes: true }` to avoid extra stat calls
- fix: catch and report errors gracefully during skills directory enumeration instead of crashing
* docs(skill-format-check): clarify `metadata` requirement in README
test(pr-labels): add edge case samples for skills paths, CCM multi-paths, and renames
* test(pr-labels): add real PR edge case samples
- use PR #134 to test skill path behaviors
- use PR #57 to test multi-path CCM resolution
- use PR #11 to test track renames cross domains
* refactor(ci): migrate pr labels from area to domain prefix
- Replaced `area/` prefix with `domain/` for PR labeling to align with existing GitHub labels
- Renamed internal constants and variables from `area` to `domain` (e.g. `PATH_TO_AREA_MAP` to `PATH_TO_DOMAIN_MAP`)
- Updated `samples.json` test data to use new `domain/` format and `expected_domains` key
- Added `scripts/pr-labels/test.js` runner script for continuous validation of labeling logic against PR samples
- Corrected expected size label for PR #134 test sample
* test: use execFileSync instead of execSync in pr-labels test script
* fix: resolve target path against process.cwd() instead of __dirname in skill-format-check
* docs: correct label prefix in PR label workflow README
- Updated README.md to reflect the new `domain/` label prefix instead of `area/`
* fix(ci): fix dry-run console output formatting and enforce auth in tests
- Removed duplicate domain array interpolation in printDryRunResult
- Added process.env.GITHUB_TOKEN guard in test.js to prevent ambiguous failures from API rate limits
* fix(ci): ensure PR labels can be applied reliably
- Added `issues: write` permission to pr-labels workflow, which is strictly required by the GitHub REST API to modify labels on pull requests
- Reordered script execution in `index.js` to apply/remove labels on the PR *before* attempting to sync repository-level label definitions (colors/descriptions). The definition sync is now a trailing best-effort step with error catching so transient repo-level API failures don't abort the critical path.
* fix(ci): fix edge cases in pr-label index script
- Added missing `skills/lark-task/` to `PATH_TO_DOMAIN_MAP` to properly detect task domain modifications
- Updated GitHub REST API error checking in `syncLabelDefinition` to reliably match `error.status === 422` rather than loosely checking substring
- Moved token presence check in `main()` to happen before `resolveContext` to avoid triggering unauthenticated 401 API limits when GITHUB_TOKEN is omitted locally
* test(ci): clean up PR label test samples
- Removed duplicate PR entries (#11 and #57) to reduce redundant API calls during testing
- Renamed sample test cases to correctly reflect their expected labels (e.g. `size-l-skill-format-check` -> `size-m-skill-format-check`)
* fix(ci): bootstrap new labels before applying to PRs
- Prior changes correctly made full label sync best-effort, but broke the flow for brand new domains
- GitHub API returns a 422 error if you attempt to attach a label to an Issue/PR that does not exist in the repository
- Added a targeted bootstrap loop to create/sync specifically the labels in `toAdd` before attempting `client.addLabels()`
- Left the remaining global label synchronization as a best-effort trailing action
* test(ci): automate PR label regression testing
- Added a dedicated GitHub Actions workflow (`pr-labels-test.yml`) to automatically run `test.js` against `samples.json` whenever the labeling logic is updated
- Documented local testing instructions in `scripts/pr-labels/README.md`
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mail): auto-resolve local image paths in draft body HTML (#81)
Allow <img src="./local/path.png" /> in set_body/set_reply_body HTML.
Local file paths are automatically resolved into inline MIME parts with
generated CIDs, eliminating the need to manually pair add_inline with
set_body. Removing or replacing an <img> tag in the body automatically
cleans up or replaces the corresponding MIME inline part.
- Add postProcessInlineImages to unify resolve, validate, and orphan
cleanup into a single post-processing step
- Extract loadAndAttachInline shared helper to deduplicate addInline
and resolveLocalImgSrc logic
- Cache resolved paths so the same file is only attached once
- Use whitelist URI scheme detection instead of blacklist
- Remove dead validateInlineCIDAfterApply and
validateOrphanedInlineCIDAfterApply functions
Closes#81
* fix(mail): harden inline image CID handling
1. Fix imgSrcRegexp to skip attribute names like data-src/x-src that
contain "src" as a suffix — only match the real src attribute.
2. Sanitize cidFromFileName to replace whitespace with hyphens,
producing RFC-safe CID tokens (e.g. "my logo.png" → "my-logo").
3. Add CID validation in newInlinePart to reject spaces, tabs, angle
brackets, and parentheses — fail fast instead of silently producing
broken inline images in the sent email.
* refactor(mail): use UUID for auto-generated inline CIDs
Replace filename-derived CID generation (cidFromFileName + uniqueCID)
with UUID-based generation. UUIDs contain only [0-9a-f-] characters,
eliminating all RFC compliance risks from special characters, Unicode,
or filename collisions. Same-file deduplication via pathToCID cache
is preserved — multiple <img> tags referencing the same file still
share one MIME part and one CID.
* fix(mail): avoid panic in generateCID by using uuid.NewRandom
uuid.New() calls Must(NewRandom()) which panics if the random source
fails. Replace with uuid.NewRandom() and propagate the error through
resolveLocalImgSrc, so the CLI returns a clear error instead of
crashing in extreme environments.
* fix(mail): restore quote block hint in set_reply_body template description
The auto-resolve PR accidentally dropped "the quote block is
re-appended automatically" from the set_reply_body shape description.
Restore it alongside the new local-path support note.
* fix(mail): add orphan invariant comment and expand regex test coverage
- Add comment in postProcessInlineImages explaining that partially
attached inline parts on error are cleaned up by the next Apply.
- Add regex test cases: single-quoted src, multiple spaces before src,
and newline before src.
* fix(mail): use consistent inline predicate and safer HTML part lookup
1. removeOrphanedInlineParts: change condition from
ContentDisposition=="inline" && ContentID!="" to
isInlinePart(child) && ContentID!="", matching the predicate used
elsewhere — parts with only a ContentID (no Content-Disposition)
are now correctly cleaned up.
2. postProcessInlineImages: use findPrimaryBodyPart instead of
findPart(snapshot.Body, PrimaryHTMLPartID) to avoid stale PartID
after ops restructure the MIME tree.
* fix(mail): revert orphan cleanup to ContentDisposition check to protect HTML body
The previous change (d3d1982) broadened the orphan cleanup predicate to
isInlinePart(), which treats any part with a ContentID as inline. This
deletes the primary HTML body when it carries a Content-ID header
(valid in multipart/related), even on metadata-only edits like
set_subject.
Revert to the original ContentDisposition=="inline" && ContentID!=""
condition — only parts explicitly marked as inline attachments are
candidates for orphan removal. Add regression test covering
multipart/related with a Content-ID-bearing HTML body.
* fix: Fix the issue where the URL returned by the "lark-cli auth login --no-wait" command contains \u0026
* style: fix indentation and whitespace in error handling code
* fix(auth): handle JSON encoding errors in login output
* docs(cmd/auth): add comment for authLoginRun function