Skip to content

fix(feishu): unregister the default card handler before replacing it (node-sdk 1.74) - #231

Merged
eddiearc merged 2 commits into
eddiearc:mainfrom
itswl:fix/card-handler-unregister
Sep 14, 2026
Merged

eddiearc merged 2 commits into
eddiearc:mainfrom
itswl:fix/card-handler-unregister

Conversation

@itswl

@itswl itswl commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

What

host-channel-business.ts replaces the channel package's default card.action.trigger handler after connect(). Until now that second registration tripped the SDK's duplicate-registration path, which logged at error level on every connect/reconnect (filed as #220), and there was no supported way to replace a handler at all.

Upstream fixed the vendor side (#224larksuite/node-sdk#225): EventDispatcher.unregister(...keys) was added, the duplicate-registration log demoted to warn, and the replacement pattern documented — and @larksuiteoapi/node-sdk@1.74.0 carries it.

Change

  • package.json / bun.lock: an overrides entry pins the transitive @larksuiteoapi/node-sdk to ^1.74.0. The channel package's declared range (^1.67.0) already allows it; an override is used because Larkin imports nothing from node-sdk directly — a direct dependency would be a phantom declaration. This is the only manifest change.
  • src/feishu/host-channel-business.ts: registerCardActions now calls dispatcher.unregister?.("card.action.trigger") before installing its handler, so the deliberate replacement is no longer a duplicate registration (no line at all, not even a warn). The local Dispatcher interface gains that method as optional, with a comment on why: the channel package's published dispatcher type is narrower than the runtime dispatcher it hands over.
  • test/unit/feishu/host-channel-business.test.mjs: the real-dispatcher test now records the SDK logger and asserts no handle is registered line — which also pins the assumption that the runtime dispatcher is node-sdk >= 1.74.

Validation

  • bun test test/unit/feishu/host-channel-business.test.mjs → 8 pass / 0 fail (including the new no-duplicate-log assertion)
  • bun test test/unit/feishu/ → 138 pass / 0 fail
  • bun run build ✅ · bun run typecheck ✅ · bun run licenses:check ✅ · bun run publication:check:tree
  • bun run test:unit → 896 pass / 1 skip / 7 fail on a machine with three agents' daemons running. All seven are load/timeout flakes, each re-checked in isolation: four files pass standalone, and Agent CLI process consumes native-shaped …, the live-acceptance harness and the stale-lock reclaim guard also fail on unmodified main in this environment (verified before this change). None of them touch the SDK dispatcher or the card handler.

Shape note: the overrides pin is the one dependency-manifest change (no new dependency, no code importing node-sdk). Happy to re-shape per maintainer direction — e.g. drop the override once @larksuite/channel declares the newer range itself, or keep the plain replacement with only the lockfile bumped if overrides is not wanted.

Fixes #220

🤖 Generated with Claude Code

@eddiearc eddiearc left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Fable 5.1 review(head 9bf6507

Verdict: REQUEST_CHANGES

阻塞

  1. 测试断言空转:node-sdk 1.74 重复注册文案是 … handle is already registered and has been replaced…,PR 正则 /handle is registered/ 匹配不到。变异验证(去掉 unregister)仍 pass。请改为例如:
    assert.deepEqual(dispatchLogs, [], JSON.stringify(dispatchLogs));
    (或至少 /handle is (already )?registered/,且确认缺 unregister 时失败。)
  2. AGENTS.md:每次交付需 bump package.json patch。本 PR 仍为 0.5.9。与 #230(已占 0.5.10)协调:先合者 0.5.10,后者 rebase 到 0.5.11。

代码本身 ✅

  • unregister?.("card.action.trigger")register:与原先 Map 覆盖语义等价,只消噪音
  • overrides^1.74.0 形态合理(避免幻影 direct dep)
  • 卡片幂等 / InteractionStateMachine 无语义风险
  • CI 绿;unit host-channel-business 8/8

Nits(非阻塞)

  • bun.lock 里 node-sdk 条目 registry URL 为空,与仓库其余 npmmirror 不一致,建议一致 registry 重生成
  • Dispatcher 注释可改为「channel 未公开 dispatcher 类型,Larkin 本地结构类型描述运行时 node-sdk」;可考虑与 host-shell.ts 内联类型合并

合入仍等 idan 明确 yes。

@itswl

itswl commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

复审项更新(head 2e88956

  1. 测试断言空转已修:确认 node-sdk 1.74 的文案是 … handle is already registered and has been replaced, call unregister('card.action.trigger') first to replace it explicitly,旧的 /handle is registered/ 确实永远匹配不到。现改为 assert.deepEqual(dispatchLogs, [], …);变异验证:注掉 unregister?.() 后重建,该断言立即失败(失败信息里带出那条 warn 原文),恢复后 8/8 通过。
  2. version bump 已加0.5.9 → 0.5.10。若与 feat(runtime): optional dedicated tmux socket (LARKIN_TMUX_SOCKET) for pi tasks #230 同批且 feat(runtime): optional dedicated tmux socket (LARKIN_TMUX_SOCKET) for pi tasks #230 先合,这边随时 rebase 到 0.5.11
  3. Dispatcher 注释已按建议改写为「channel 未公开 dispatcher 类型;此本地结构类型描述运行时 node-sdk」;与 host-shell.ts 内联类型的合并留作 follow-up。
  4. bun.lock registry URL:重新生成会让 bun install(非 frozen 模式)按 semver 范围把 100+ 个 AWS SDK 传递依赖浮动到新 patch(如 @aws-sdk/core 3.977.6 → 3.978.0),与 [Bug]: 每次连接都打印 SDK error 级 "this card.action.trigger handle is registered"(有意的 handler 替换,属噪音且易误判) #220 无关,未塞进本 PR;保持现有 lock(CI 此前即用此 lock 绿色安装)。若要一致化,建议单独开一个依赖刷新。

本地重跑:test/unit/feishu/ 138 pass / 0 fail;test/unit/runtime/ 237 pass / 0 fail;bun run build / typecheck / licenses:check / publication:check:tree ✅。CI 已触发。

@eddiearc eddiearc left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Fable 5.1 re-review(head 2e88956

Verdict: APPROVE_WITH_NITS

上轮阻塞均已解决:

  1. assert.deepEqual(dispatchLogs, []) — 变异验证:去掉 unregister 后捕获 node-sdk 1.74 的 already registered … replaced warn 并失败;恢复后通过
  2. package.json 0.5.9 → 0.5.10

overrides + unregister→register 语义 OK;CI 绿。

Nits:bun.lock node-sdk registry URL 为空;与 #230/#224/#226/#222/#233 版本号撞车,先合者占 0.5.10,其余 rebase。

合入仍等 idan 明确 yes。

itswl and others added 2 commits September 14, 2026 14:54
Replacing the channel package's card.action.trigger handler was a second
registration, which node-sdk logged at error level on every connect and
reconnect (eddiearc#220) with no supported way to replace a handler. Upstream now
provides EventDispatcher.unregister and demotes the duplicate log to warn
(larksuite/node-sdk#225, @larksuiteoapi/node-sdk@1.74.0): pin that version
through an overrides entry and unregister before registering, so the
deliberate replacement produces no log line at all.

The card-registration test asserts the SDK logger stays empty: node-sdk
1.74 warns "… handle is already registered and has been replaced …",
which the previous /handle is registered/ regex could never match;
dropping the unregister call now fails the assertion (mutation-checked).

Bumps the package patch version (0.5.9 -> 0.5.10) per the Owner policy.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-authored-by: idan <eddiearc6@gmail.com>
@cursor
cursor Bot force-pushed the fix/card-handler-unregister branch from 2e88956 to 76e3f50 Compare September 14, 2026 14:54
@eddiearc
eddiearc merged commit cd57343 into eddiearc:main Sep 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 每次连接都打印 SDK error 级 "this card.action.trigger handle is registered"(有意的 handler 替换,属噪音且易误判)

3 participants