Commit Graph

972 Commits

Author SHA1 Message Date
shanglei
0885ec2eae fix(qualitygate): give both layering walks one scope
The constraint walk descended into nested modules while the file walk skipped
them, and the two feed each other: constraints become the configurations the
file walk is measured against. A compound tag under lint/ therefore added
`-tags bar,foo` to this module's sweep — seven more `go list` runs selecting
nothing here, and a failing configuration list — over a file no walk ever
required to be selected. lint/ carries no custom tag today, so the divergence
was latent rather than broken.

One predicate now answers both walks, and a test pins it: a nested module is out
of scope, a plain package directory is not, and the module root itself stays in.
2026-07-29 16:20:50 +08:00
shanglei
b39258c169 fix(shortcuts): stop printing the import alias as the brand word
The internal/core split renamed the brand package and aliased the import as
brandpkg, and the sweep that rewrote `brand.` also rewrote the word ending three
sentences. One of them is user-visible: `apps --help` on Lark read "The "apps"
feature is not yet supported on the lark brandpkg." The error path a few lines
above was spelled without the trailing period and escaped the sweep, so the two
surfaces disagreed.

The brand-guard tests only exercised RunE, which --help bypasses, so nothing
covered the sentence. Pin it whole: a substring check would still pass on a
mangled tail.

The other two are comments in internal/auth.
2026-07-29 15:27:32 +08:00
shanglei
2a252d2a80 fix(qualitygate): select build-tag files the union used to miss
The union executed one `go list` per registered tag, so a file constrained by
`foo && bar` was selected by neither `-tags foo` nor `-tags bar`. The coverage
test only asked whether each tag name appeared in the registry, which both did,
and the remedy it printed — "union the tag" — is what produced the gap: register
the two tags separately and the file lands in no graph while every check reports
covered. A probe file under events/ importing shortcuts/common, the exact shape
events-no-shortcuts forbids, passed the whole suite that way.

Derive the configurations instead. Every //go:build line is parsed with
go/build/constraint, and each distinct expression contributes a tag set that
satisfies it, so `foo && bar` yields `-tags bar,foo` without anyone registering
anything. Platform terms stay free variables: layeringBuildTargets already
varies GOOS and GOARCH, and -tags cannot set them. Cheapest set wins, which
keeps a platform-only constraint from adding a configuration it does not need.

Deriving the sets removes both hand-kept lists, including the exclusion map that
carved out the sidecar demo tags — those now get a configuration like everything
else.

The replacement invariant is a file-level one the tag registry could not state:
every Go file in this module must be compiled by at least one executed
configuration, asked of the toolchain rather than re-derived from the model that
produced the configurations. It immediately found a second blind spot with no
custom tag in it at all: internal/riskcontrol/osmodel_other.go is constrained
`!darwin && !windows && !linux`, and all seven release targets are one of those,
so no configuration has ever compiled it. That file is recorded as out of scope
with its reason checked — an entry naming a custom tag, or one a release target
does compile, now fails.

Nested modules are skipped, since `go list ./...` does not reach into lint/ and
the rules are written against this module's import paths.

Cost: the file-level check sweeps `go list` again because the rule graph merges
packages across configurations and keeps only imports, so it can no longer say
which configuration contributed which file. The package goes from roughly 16s to
roughly 60s.
2026-07-29 15:27:20 +08:00
shanglei
1ba4d1fd77 Merge remote-tracking branch 'origin/main' into refactor/package-debt-phase2
Two conflicts, both in the calendar rich-image preview URL and both the same
shape: main fixed the default host while this branch renamed the brand type.
Took main's fix and this branch's package.

- shortcuts/calendar/description_rich_images.go: host stays the feishu.cn value
  #2079 corrected it to, with the brandpkg.Brand signature.
- shortcuts/calendar/description_rich_images_test.go: the expected host fragment
  follows the same fix; the table already carried brandpkg.Brand from the
  automatic merge, so core.Brand* would not have compiled.
2026-07-29 14:18:27 +08:00
R0bynZhu
358cd06838 docs(slides): 补齐 shortcut 参数说明,修正 +xml-get --output 必填标注 (#2088)
* docs(slides): consolidate CWD-relative path rule into one global rule

State the "all local file path args must be CWD-relative (absolute
rejected)" rule once in SKILL.md 权威经验, and trim the per-command
repetitions in media-upload / create / screenshot / xml-presentations-get.
Also fix the stale xml-presentations-get param table: --output is optional
(relative), not required.

* feat: try common solution

* chore: 优化措辞

* feat: 优化措辞

* feat: 优化措辞

* docs(slides): 强调调用命令前必读对应命令文档

- 「调用命令前再读」改为「调用相关命令前必须读取相关的文档以了解命令的使用方式」,
  并把原「按需再读」列表合并进来,去掉可选语义
- 移除 lark-shared 的 CRITICAL 前置阅读要求
- Step 4 回读示例补全 `--presentation <xml_presentation_id>` 参数

* docs(slides): Shortcuts 表补充 +screenshot 并写明本地路径参数

- 新增 +screenshot 行:--slide-number 页号(从 1 开始,可重复,一次最多 10 页)、
  --output-dir 保存目录(CWD 内相对路径,默认 .lark-slides/screenshots)
- +xml-get 行补上 --presentation 和 --output(CWD 内相对路径),
  并说明省略 --output 时 XML 返回在 JSON 信封里

* revert(slides): 回退 references 下的文档改动,只保留 SKILL.md

把 lark-slides-create.md、lark-slides-media-upload.md、lark-slides-screenshot.md、
lark-slides-xml-presentations-get.md 还原为 main 的版本,本分支只改 SKILL.md。

* docs(slides): 恢复开始前必读 lark-shared 的 CRITICAL 要求

认证、权限和全局参数以 lark-shared 为准,这条前置阅读不该在本分支被删掉。

* chore: 移除output省略的说明
2026-07-29 10:55:05 +08:00
Yuxuan Zhao
b0b1ca4b5d test(e2e): wait for base role update visibility (#2087) 2026-07-28 21:45:00 +08:00
liangshuo-1
781d188a60 chore: release v1.0.79 (#2082) v1.0.79 2026-07-28 21:02:37 +08:00
calendar-assistant
2e0fb9a880 docs(calendar): refine attendee guidance for bots and user-search identity (#2086)
Consolidate the user-search identity note into SKILL.md, and clarify bot
handling across attendee flows: bots are virtual identities with no
free/busy semantics, no meeting-room seat, and no room preference, so
they must be excluded from +suggestion, +room-find, and the scheduling
free/busy check. Note in create/update that bots remain valid attendees.
2026-07-28 20:34:09 +08:00
ILUO
927b37cd63 docs(task): document create data passthrough (#2080) 2026-07-28 20:26:35 +08:00
zhangjun-bytedance
d2e22c5fca feat: 0728 fix url (#2079) 2026-07-28 19:05:47 +08:00
ethan-zhx
fdae560014 docs(slides): add formula inline element syntax to quick-ref (#2077)
* docs(slides): add formula inline element syntax to quick-ref

* docs(slides): add chart gradient syntax to quick-ref
2026-07-28 17:40:54 +08:00
shanglei
bb7342c3cc docs: record what internal/core became in the source layout
The split left the layout table naming only the renamed config package, so
brand, workspace and identity — the three a caller reaches for most — had no
entry, and nothing said where the remaining two went. brand earns a row of its
own for a second reason: it sits at the repository root precisely so extension/
may import it.

The note under the table carries what a path table cannot. The five siblings do
not import each other, and that is the whole reason to ask for the narrow one:
a caller that only wants a config directory no longer compiles keychain, i18n
and validate along with it.
2026-07-28 16:30:30 +08:00
shanglei
f25ef0ae75 docs: point the moved core references at their new packages
The internal/core split renamed or relocated every symbol these comments
name, and the sweep missed six call-outs. Two had gone self-contradictory:
internal/meta named the package internal/core while already qualifying the
type as identity.Identity, and authlog attributed its runtime-directory
indirection to a cycle through internal/core that the split removed.

Restate authlog's reason for keeping the indirection instead of promising a
follow-up: the factory-installed logger follows the detected workspace while
the Shared() fallback stays on the pre-workspace directory, so resolving the
directory inside the package would collapse that distinction.

The domaincontract rule's README still pointed host literals at
internal/core/types.go; the exemption moved to brand/brand.go with the
resolver.
2026-07-28 15:36:35 +08:00
zhengzhijiej-tech
1b173e1953 fix(sheets): recognize OFL0X local office tokens (#2063) 2026-07-28 15:09:42 +08:00
shanglei
5bae5bbbc2 fix(lint): follow the extracted brand resolver 2026-07-28 14:50:25 +08:00
ethan-zhx
57db1b3a8d feat(slides):update xsd (#2067) 2026-07-28 14:43:15 +08:00
shanglei
d7cf797bdd refactor(config): remove unreachable legacy loaders 2026-07-28 14:40:30 +08:00
shanglei
0266a7e9a1 refactor(core): rename remaining config package 2026-07-28 14:16:38 +08:00
shanglei
939fc1eeb8 refactor(core): extract identity policy 2026-07-28 14:12:20 +08:00
calendar-assistant
4c1c5f5287 docs(calendar): clarify identity selection by event ownership (#2071)
Reframe the identity section around event ownership: use `--as user`
for the logged-in user's own events and `--as bot` for events the bot
creates or participates in, with matching `+agenda` examples.
2026-07-28 14:05:21 +08:00
shanglei
c69a61c672 refactor(core): extract secret storage 2026-07-28 14:04:51 +08:00
shanglei
ee27d0cdc2 refactor(core): extract workspace paths 2026-07-28 12:15:26 +08:00
shanglei
3732c6bcce refactor(core): extract brand package 2026-07-28 12:10:53 +08:00
shanglei
9d8e93c682 refactor(core): extract risk constants 2026-07-28 12:00:36 +08:00
shanglei
38312d3a9c refactor(apps): move local state behind internal storage 2026-07-28 11:58:22 +08:00
shanglei
342d1a247d refactor(shortcuts): centralize output directory creation 2026-07-28 11:53:54 +08:00
shanglei
770c23035c refactor(shortcuts): route client helpers through common 2026-07-28 11:48:37 +08:00
shanglei
2634092ff2 refactor(shortcuts): route scope checks through common 2026-07-28 11:45:57 +08:00
liangshuo-1
3d2c10cd0b fix(ci): validate static workflow identity (#2015) 2026-07-27 19:39:11 +08:00
liangshuo-1
03de81c5f3 chore: release v1.0.78 (#2061) v1.0.78 2026-07-27 19:17:53 +08:00
shanglei
9c50045f14 docs(authlog): drop the pointer to a note that was never written
The comment sent readers to a follow-up in the pull request description that
does not exist there. Keep the reason in the source, where it is already
complete, and add the evidence that made the decision: applying the validator
moved four packages' expectations from /var to /private/var, because it
resolves symlinks.
2026-07-27 17:45:07 +08:00
shanglei
7b6962a726 fix(sidecar): keep the classification the resolver already made
97e397cf classified every startup failure, including the one the config
resolver had already classified. An unconfigured CLI comes back as
not_configured carrying "run: lark-cli config init"; wrapping it in
invalid_config put the wrong subtype in front — ProblemOf reads the outermost —
and dropped the hint entirely. A caller would be told the config is broken when
it was never written.

Pass typed errors through untouched and reserve a fresh error for the case
where the resolver gave none, where internal/unknown is the honest answer
rather than a guess at invalid_config.

Flag rejections now name the flag through WithParam, so a caller learns which
one to fix without reading the sentence, and the tests assert subtype and
param through ProblemOf instead of matching prose.
2026-07-27 17:45:07 +08:00
shanglei
1af34e6649 docs(authlog): correct what the word cap is measuring
The comment claimed the binary plus two words is the deepest command path in
this CLI. It is not: generated service commands go one level further, as
`drive file.comments create_v2` in the manifest tests shows, and the cap cuts
their last word. Calling the bound a measurement invites the next reader to
raise it for a command that does not fit — which would also admit the first
positional argument, where resource identifiers live.

State it as the privacy bound it is, and add the generated-command case to the
table so the trade-off is visible next to the cases it protects.
2026-07-27 17:29:18 +08:00
yballul-bytedance
7abcaa7f68 feat(drive): add title+body joint search guidance and Top N pagination rules (#2059)
* feat(drive): add title+body joint search guidance and pagination rules for Top N results

- Add new blockquote explaining combined title+body search: use a single
  --query with both keywords instead of splitting into two searches
- Add rule for Top N results: N is an output cap, not --page-size; scan
  up to 3 pages filtering by title and summary_highlighted, read body
  only for title-matched candidates, stop early at N confirmed results
- Add quick-reference table row for folder-scoped title+body search
- Update pagination strategy rule to cover the 3-page cap for joint
  search in addition to the existing 5-page limit for other scenarios

* feat(drive): clarify Top N search output limit

* feat(drive): clarify search filters share one call

---------

Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com>
2026-07-27 17:19:48 +08:00
shanglei
c12ab91349 fix(authlog): restore the word cap the flag boundary replaced
475f04a8 stopped the command line at the first flag and dropped the
"keep three words" rule with it, on the reasoning that the command path is what
the log needs. That reasoning missed positional arguments: `api <method> <path>`
takes the path as an argument, so a document token moved from truncated to
recorded in a file that is kept for a week.

Apply both limits. Stop at the first flag, so a sensitive flag ahead of the
subcommand cannot slip through, and keep at most three words, so a positional
identifier after the command path cannot either. Removing either one fails a
test: the flag boundary alone lets the document token through, the word cap
alone lets --token=... through.

Verified case by case that nothing reaches the log that the pre-475f04a8
behaviour withheld.
2026-07-27 17:08:38 +08:00
shanglei
57bf8ccd1e docs(authlog): record why two neighbours read the environment differently
LARKSUITE_CLI_LOG_DIR is validated, LARKSUITE_CLI_CONFIG_DIR is not, and the
asymmetry looks like an oversight. It is not free to remove:
validate.SafeEnvDirPath resolves symlinks, so routing CONFIG_DIR through it
changes the directory the CLI reports on any host where the path crosses one.
Applying it moved four packages' expectations from /var to /private/var on
macOS. Whether config paths should be symlink-resolved is a decision about the
on-disk contract, not a local tidy-up, so say so where the next reader looks.

Also record why the stderr capture helper uses os while the file assertions use
vfs: os.Pipe and os.Stderr are process contracts with nothing for a substituted
filesystem to intercept.
2026-07-27 16:42:20 +08:00
shanglei
97e397cf0c refactor(sidecar): return typed errors from the demo servers
Both demo entry points reported every startup failure with fmt.Errorf, so the
self-proxy rejection was indistinguishable from a missing key file except by
reading the sentence. Classify them instead: a poisoned environment and an
unreadable config are ConfigError, flag validation is ValidationError, local
key and log file work is InternalError, and listen or serve failures are
NetworkError. Causes are attached rather than folded into the message.

The self-proxy test asserts the type with errors.As and keeps the check that
the message names the variable, so renaming the variable still fails the test
while rewording the sentence no longer does.
2026-07-27 16:42:20 +08:00
zhangjun-bytedance
8fb2476985 0727 fix rich text (#2062) 2026-07-27 16:17:08 +08:00
shanglei
c138f29972 Merge remote-tracking branch 'origin/main' into refactor/package-debt-phase2 2026-07-27 15:45:58 +08:00
shanglei
2662729cd6 test(core): enforce the brand parity the comments only request
bf56e903 asked the next author to change both ParseBrand implementations by
cross-referencing them. That is the weakest kind of guarantee: it holds until
someone adds a brand to the package they happened to open.

Assert it instead. The constants are read out of both sources rather than
listed again, so a brand added to one package is under test immediately, and
the two parsers are compared on every declared value plus the inputs that
exercise the normalisation — case, padding, an unknown brand, a near miss.

The file sits in neither parser's package so neither owns the contract. It does
not merge the two implementations: extension/credential ships as a standalone
SDK and may not import internal, which is the constraint this branch exists to
establish.
2026-07-27 15:43:46 +08:00
shanglei
475f04a8dd fix(authlog): stop trusting argument position, and speak up on a rejected log dir
Two behaviours carried over from internal/keychain, both left as they were when
the package moved.

FormatAuthCmdline kept the first three arguments. That protected secrets only
while no sensitive flag appeared early: a global flag in front of the
subcommand put its value straight into a file that is world-readable to the
user, kept for seven days. Today's CLI cannot reach that state — the only
persistent flag is --profile and secrets arrive through --app-secret-stdin — so
this is about the shape, not a live leak. Drop everything from the first flag
onward instead. A denylist of sensitive names would need extending whenever one
is added; the command path is what the log is for, and it lives entirely in the
leading non-flag arguments. args[0] is reduced to its base name so an absolute
install path stays out too.

logDir swallowed the error when LARKSUITE_CLI_LOG_DIR failed validation and
wrote elsewhere while the caller kept watching the path they configured. Warn
instead. This fires only on a rejected override, not on every run, and logDir
resolves once per process.

Tests cover a flag ahead of the subcommand, the absolute-path case, and that a
usable override still prints nothing.
2026-07-27 15:43:46 +08:00
shanglei
52a1187c20 test(qualitygate): detect build tags the union never scans
The build-tag list was checked against a literal, so the test only caught edits
to the list itself. A tag introduced anywhere else left its files out of every
graph and the rules went quiet on them, with nothing to notice. The platform
list does not have this hole: it is cross-checked against .goreleaser.yml.

Walk the tree for //go:build constraints and require every custom tag to be
either unioned or listed as excluded. GOOS, GOARCH and toolchain terms come
from `go tool dist list` so a new port cannot look like a custom tag.

Exclusions now carry a reason that is verified rather than asserted: the two
demo tags are skipped because their files sit outside every rule's FromPrefix,
and the test fails if a file carrying one ever lands inside one. A listed
exclusion nobody uses fails too, so the list cannot rot.
2026-07-27 15:23:02 +08:00
shanglei
bf56e903ba docs: point the two brand parsers at each other
Removing extension's dependency on internal left the brand rule implemented
twice, once per Brand type. The two cannot share code: extension is published
as a standalone SDK and may not import internal, which is the constraint this
branch exists to establish. Cross-reference them so a third brand is added to
both rather than to whichever one the next author happens to open.

Also correct the timestamp wrapper's comment, which has claimed "HH:mm" since
before this branch while every implementation formatted seconds too.
2026-07-27 14:37:02 +08:00
shanglei
b028c33e8f fix(authlog): keep the installed logger for the life of the process
The package documents one logger and one file handle per process, but SetShared
overwrote the current instance on every call and the factory can be built more
than once. A second construction opened a second file, left the first one open
with no way to close it, and moved later lines to whichever workspace directory
that construction resolved.

Only the first explicit install now takes effect. A lazily created fallback is
not an explicit install, so the first real one still replaces it — and closes
the file it had opened, which needs the handle to be retained rather than
handed to log.New and forgotten. The once-guarded init becomes a mutex so the
handle can be released safely; a closed logger drops writes instead of pointing
at a file nobody reads.

Tests cover two non-nil installs and the fallback handover, and both fail if
the guard is removed.
2026-07-27 14:14:10 +08:00
shanglei
4073e75def fix(qualitygate): exempt single edges instead of whole packages
Two packages were listed in ExceptFrom, which makes the evaluator skip the
source package before it looks at any dependency. gitcred needs keychain and
vfs; manifest-export needs the cmd root. Exempting them wholesale also cleared
every other denied import, so a later gitcred -> internal/client or
manifest-export -> events would pass the gate and never reach the registry. A
probe confirmed both slip through unreported.

Add ExceptEdges, matched on the exact (from, denied) pair, and move these two
across. ExceptFrom stays for packages whose whole job is to sit on the boundary
the rule draws: the shortcuts/common runtime gate, the cmd assembly roots, the
wrapper-main demos. Contract tests feed each package its allowed imports plus
one denied import and assert exactly one violation, so the allowed edges carry
weight instead of being asserted trivially.
2026-07-27 14:14:10 +08:00
zhanghuanxu
56c9a2afd8 fix: exempt ghost text from slides lint 2026-07-27 11:59:04 +08:00
zhanghuanxu
2029189809 fix(slides):text may over flow shape 2026-07-27 11:59:04 +08:00
zhanghuanxu
ee427979a8 fix(slides): preserve info lint severity 2026-07-27 11:59:04 +08:00
zhanghuanxu
545abcbbde fix: refine character width estimation for lark-slides text lint
Replace the uniform 0.55em half-width coefficient with per-character-type
coefficients, add font-family awareness (sans/serif), bold multiplier,
letter-spacing support, and fix padding-aware line wrapping.

- Split half-width chars into uppercase (0.57), lowercase (0.51 sans / 0.53
  serif), digits (0.58), and punctuation (0.50)
- Add classify_font_family() to apply slightly wider lowercase widths for
  serif fonts (Georgia, Source Han Serif/思源宋体, Times, etc.)
- Add 5% width multiplier for bold text; detect <strong>/<b>/<i>/<em> tags
  and span-level bold/italic attributes in addition to content attrs
- Fix estimate_text_line_count_for_text to subtract paddingLeft/paddingRight
  from available width before computing wrap lines
- Add resolve_letter_spacing and wire letterSpacing through estimate_text_width
- Extract fontFamily/bold/italic/letterSpacing into element dict during parse
2026-07-27 11:59:04 +08:00
zhanghuanxu
4a73e83f1e fix(slides): allow chartParsedValues roundtrip tag
chartParsedValues is a server-injected roundtrip child tag under
chartField, not an attribute. Move it from ROUNDTRIP_SXSD_ATTRS to a
new ROUNDTRIP_SXSD_TAGS set and skip the tag (and its subtree) in the
SXSD tag whitelist check.
2026-07-27 11:59:04 +08:00